home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianControls.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  129KB  |  5,653 lines

  1. /*ScianControls.c
  2.   Controls, control panel stuff, etc. for scian
  3.   Eric Pepke
  4.   March 28, 1990
  5. */
  6.  
  7. #include "Scian.h"
  8. #include "ScianTypes.h"
  9. #include "ScianLists.h"
  10. #include "ScianControls.h"
  11. #include "ScianButtons.h"
  12. #include "ScianTitleBoxes.h"
  13. #include "ScianColors.h"
  14. #include "ScianIDs.h"
  15. #include "ScianSliders.h"
  16. #include "ScianTextBoxes.h"
  17. #include "ScianArrays.h"
  18. #include "ScianErrors.h"
  19. #include "ScianWindows.h"
  20. #include "ScianDraw.h"
  21. #include "ScianEvents.h"
  22. #include "ScianObjWindows.h"
  23. #include "ScianVisWindows.h"
  24. #include "ScianIcons.h"
  25. #include "ScianMethods.h"
  26. #include "ScianScripts.h"
  27. #include "ScianStyle.h"
  28. #include "ScianHelp.h"
  29. #include "ScianPreferences.h"
  30. #include "ScianObjFunctions.h"
  31. #include "ScianSymbols.h"
  32. #include "ScianTrackControls.h"
  33. #include "ScianScales.h"
  34. #include "ScianDialogs.h"
  35. #include "ScianTemplates.h"
  36. #include "ScianTemplateHelper.h"
  37. #include "ScianDepend.h"
  38. #include "ScianSnap.h"
  39. #include "ScianColorControls.h"
  40.  
  41. ObjPtr tempRepObj;            /*Temporary icon*/
  42. ObjPtr screenClass = NULLOBJ;        /*Class of all screen objects*/
  43. ObjPtr controlClass = NULLOBJ;        /*Great mother of all controls*/
  44. ObjPtr fieldClass = NULLOBJ;
  45. ObjPtr panelClass = NULLOBJ;
  46. ObjPtr greyPanelClass = NULLOBJ;    /*A panel with a grey background*/
  47. ObjPtr corralClass = NULLOBJ;
  48. ObjPtr switchClass = NULLOBJ;
  49. ObjPtr controlFieldClass = NULLOBJ;    /*Text field class*/
  50.  
  51. #define EDITGRAVITY    4
  52. #define CELLHEIGHT    25        /*Height of a cell*/
  53. #define CELLFONTSIZE    12.0        /*Size of font in a cell*/
  54. #define CELLTEXTDOWN    18        /*Offset of text from top of a cell*/
  55. #define CELLTEXTRIGHT    6        /*Offset from left*/
  56. #define CELLNAMEWIDTH    150        /*Width of a name*/
  57.  
  58. #define VB_ICON        1        /*View by icon*/
  59. #define VB_NAME        2        /*View by name*/
  60.  
  61. #define LABELFONTSIZE   12.0        /* size in points of label type */
  62. #define LABELFONTFUDGE  1           /* fudge strings up (or <0 = down) to center */
  63.  
  64. #define SWITCHRADIUS    15        /*Radius of a turn on a switch*/
  65. #define SWITCHSLOPLEFT    10        /*Pixels to slop the center of a switch left*/
  66. #define ARROWLENGTH    12        /*Length of an arrow*/
  67. #define ARROWHEIGHT    6        /*Height of an arrow*/
  68.  
  69.  
  70. ObjPtr flowLineClass;
  71. #define FLOWARROWLENGTH    8        /*Length of an arrow*/
  72. #define FLOWARROWHEIGHT    4        /*Height of an arrow*/
  73.  
  74. real xGrid = 16.0, yGrid = 16.0;    /*x and y grid steps*/
  75. real xMid = 0.0, yMid = 0.0;        /*Midpoint of grid*/
  76.  
  77. static Bool IconConflict(ObjPtr, int, int);
  78.  
  79. #define GETSCROLL(object, xOff, yOff)                    \
  80.     {                                \
  81.         ObjPtr var;                            \
  82.         var = GetVar(object, VSCROLL);                \
  83.         if (var) yOff = -(int) GetSliderValue(var);            \
  84.         else yOff = 0;                        \
  85.         var = GetVar(object, HSCROLL);                \
  86.         if (var) xOff = -(int) GetSliderValue(var);            \
  87.         else xOff = 0;                        \
  88.     }
  89.        
  90. void StartPanel(left, right, bottom, top)
  91. int left, right, bottom, top;
  92. {
  93.     SetClipRect(left, right, bottom, top);
  94.     SetOrigin(left, bottom);
  95. }
  96.  
  97. void StopPanel()
  98. {
  99.     RestoreOrigin();
  100.     RestoreClipRect();
  101. }
  102.  
  103. ObjPtr PanelBoundsInvalid(object, changeCount)
  104. ObjPtr object;
  105. unsigned long changeCount;
  106. /*For an object, tests to see if it needs drawing.  Returns
  107.   NULLOBJ    if it does not
  108.   array[4]    giving bounds if it does
  109.   ObjTrue    it it needs to be redrawn but does not know where
  110.  
  111.   Contents are assumed to be shifted in the bounds of owner
  112. */
  113. {
  114.     ObjPtr contents;
  115.     ObjPtr myBounds;
  116.     FuncTyp method;
  117.     Bool firstTime;
  118.     real boundsElements[4];
  119.     Bool doubleNoBounds = false;
  120.     Bool fromTop;
  121.     Bool possiblyOpaque;
  122.  
  123.     firstTime = true;
  124.     possiblyOpaque = invalidFound ? false : true;
  125.  
  126.     MakeVar(object, APPEARANCE);
  127.  
  128.     fromTop = GetPredicate(object, TOPDOWN);
  129.  
  130.     MakeVar(object, CHANGEDBOUNDS);
  131.     if (GetVarChangeCount(object, CHANGEDBOUNDS) > changeCount)
  132.     {
  133.     /*Object is not good, so return the bounds*/
  134.  
  135.     myBounds = GetVar(object, CHANGEDBOUNDS);
  136.     if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  137.         && DIMS(myBounds)[0] == 4)
  138.     {
  139.         firstTime = false;
  140.         Array2CArray(boundsElements, myBounds);
  141.         possiblyOpaque = false;
  142.     }
  143.     else
  144.     {
  145.         /*Pathological case*/
  146.         return ObjTrue;
  147.     }
  148.     }
  149.  
  150.     MakeVar(object, CONTENTS);
  151.     contents = GetVar(object, CONTENTS);
  152.     if (contents && IsList(contents))
  153.     {
  154.     /*Still, maybe some of the contents need to be drawn*/
  155.     real testElements[4];
  156.     real myBoundsElements[4];
  157.      ObjPtr test;
  158.      ThingListPtr runner;
  159.  
  160.     MakeVar(object, BOUNDS);
  161.     myBounds = GetVar(object, BOUNDS);
  162.     Array2CArray(myBoundsElements, myBounds);
  163.  
  164.     runner = LISTOF(contents);
  165.     while (runner)
  166.     {
  167.         test = BoundsInvalid(runner -> thing, changeCount);
  168.         if (test)
  169.         {
  170.         /*Hey, the kid needs redrawing*/
  171.         if (IsRealArray(test))
  172.         {
  173.             /*It has a bounds*/
  174.             if (firstTime)
  175.             {
  176.             Array2CArray(boundsElements, test);
  177.             if (fromTop)
  178.             {
  179.                 boundsElements[0] += myBoundsElements[0];
  180.                 boundsElements[1] += myBoundsElements[0];
  181.                 boundsElements[2] += myBoundsElements[3];
  182.                 boundsElements[3] += myBoundsElements[3];
  183.             }
  184.             else
  185.             {
  186.                 boundsElements[0] += myBoundsElements[0];
  187.                 boundsElements[1] += myBoundsElements[0];
  188.                 boundsElements[2] += myBoundsElements[2];
  189.                 boundsElements[3] += myBoundsElements[2];
  190.             }
  191.             MakeVar(runner -> thing, OPAQUE);
  192.             if (GetPredicate(runner -> thing, OPAQUE))
  193.             {
  194.             }
  195.             else
  196.             {
  197.                 possiblyOpaque = false;
  198.             }
  199.             }
  200.             else
  201.             {
  202.             possiblyOpaque = false;
  203.             Array2CArray(testElements, test);
  204.             if (fromTop)
  205.             {
  206.                 testElements[0] += myBoundsElements[0];
  207.                 testElements[1] += myBoundsElements[0];
  208.                 testElements[2] += myBoundsElements[3];
  209.                 testElements[3] += myBoundsElements[3];
  210.             }
  211.             else
  212.             {
  213.                 testElements[0] += myBoundsElements[0];
  214.                 testElements[1] += myBoundsElements[0];
  215.                 testElements[2] += myBoundsElements[2];
  216.                 testElements[3] += myBoundsElements[2];
  217.             }
  218.             if (testElements[0] < boundsElements[0])
  219.                 boundsElements[0] = testElements[0];
  220.             if (testElements[1] > boundsElements[1])
  221.                 boundsElements[1] = testElements[1];
  222.             if (testElements[2] < boundsElements[2])
  223.                 boundsElements[2] = testElements[2];
  224.             if (testElements[3] > boundsElements[3])
  225.                 boundsElements[3] = testElements[3];
  226.             }
  227.         }
  228.         else
  229.         {
  230.             /*It doesn't have a bounds*/
  231.             if (firstTime)
  232.             {
  233.             /*Try to use my bounds*/
  234.             if (myBounds && IsArray(myBounds) && RANK(myBounds) == 1
  235.                 && DIMS(myBounds)[0] == 4)
  236.             {
  237.                 Array2CArray(boundsElements, myBounds);
  238.             }
  239.             else
  240.             {
  241.                 doubleNoBounds = true;
  242.             }
  243.             }
  244.         }
  245.         firstTime = false;
  246.         }
  247.         runner = runner -> next;
  248.     }
  249.     }
  250.  
  251.     /*Now return the bounds*/
  252.     if (firstTime != true)
  253.     {
  254. #ifdef DONTCLIP
  255.     possiblyOpaque = false;
  256. #endif
  257.     if (possiblyOpaque)
  258.     {
  259.         SetVar(object, BACKNOTNEEDED, ObjTrue);
  260.     }
  261.         if (doubleNoBounds)
  262.         {
  263.         return ObjTrue;
  264.         }
  265.         else
  266.         {
  267.         ObjPtr retVal;
  268.         retVal = NewRealArray(1, 4L);
  269.         CArray2Array(retVal, boundsElements);
  270.         return retVal;
  271.         }
  272.     }
  273.  
  274.     return NULLOBJ;
  275. }
  276.  
  277. #define EXPANDSHIFTEDBOUNDS(a)                    \
  278.     if (firstTime)                        \
  279.     {                            \
  280.         firstTime = false;                    \
  281.         if (IsArray(a))                    \
  282.         {                            \
  283.             Array2CArray(boundsElements, (a));        \
  284.         if (fromTop)                    \
  285.         {                        \
  286.             boundsElements[0] += myBoundsElements[0] +    \
  287.                      fieldDepth + xOff;    \
  288.             boundsElements[1] += myBoundsElements[0] +    \
  289.                      fieldDepth + xOff;    \
  290.             boundsElements[2] += myBoundsElements[3] -    \
  291.                      fieldDepth + yOff;    \
  292.             boundsElements[3] += myBoundsElements[3] -    \
  293.                      fieldDepth + yOff;    \
  294.         }                        \
  295.         else                        \
  296.         {                        \
  297.             boundsElements[0] += myBoundsElements[0] +    \
  298.                      fieldDepth + xOff;    \
  299.             boundsElements[1] += myBoundsElements[0] +    \
  300.                      fieldDepth + xOff;    \
  301.             boundsElements[2] += myBoundsElements[2] +    \
  302.                      fieldDepth + yOff;    \
  303.             boundsElements[3] += myBoundsElements[2] +    \
  304.                      fieldDepth + yOff;    \
  305.         }                        \
  306.         }                            \
  307.         else if (IsArray(myBounds))                \
  308.         {                            \
  309.             Array2CArray(boundsElements, (myBounds));    \
  310.         }                            \
  311.         else return (a);                    \
  312.     }                            \
  313.     else                            \
  314.     {                            \
  315.         real temp[4];                    \
  316.         if (IsArray(a))                    \
  317.         {                            \
  318.             Array2CArray(temp, (a));            \
  319.         if (fromTop)                    \
  320.         {                        \
  321.             temp[0] += myBoundsElements[0] +        \
  322.                     fieldDepth + xOff;    \
  323.             temp[1] += myBoundsElements[0] +        \
  324.                     fieldDepth + xOff;    \
  325.             temp[2] += myBoundsElements[3] -        \
  326.                     fieldDepth + yOff;    \
  327.             temp[3] += myBoundsElements[3] -        \
  328.                     fieldDepth + yOff;    \
  329.         }                        \
  330.         else                        \
  331.         {                        \
  332.             temp[0] += myBoundsElements[0] +        \
  333.                     fieldDepth + xOff;    \
  334.             temp[1] += myBoundsElements[0] +        \
  335.                     fieldDepth + xOff;    \
  336.             temp[2] += myBoundsElements[2] +        \
  337.                     fieldDepth + yOff;    \
  338.             temp[3] += myBoundsElements[2] +        \
  339.                     fieldDepth + yOff;    \
  340.         }                        \
  341.         }                            \
  342.         else if (IsArray(myBounds))                \
  343.         {                            \
  344.             Array2CArray(temp, (myBounds));            \
  345.         }                            \
  346.         else return (a);                    \
  347.         if (temp[0] < boundsElements[0])            \
  348.             boundsElements[0] = temp[0];        \
  349.         if (temp[1] > boundsElements[1])            \
  350.             boundsElements[1] = temp[1];        \
  351.         if (temp[2] < boundsElements[2])            \
  352.             boundsElements[2] = temp[2];        \
  353.         if (temp[3] > boundsElements[3])            \
  354.             boundsElements[3] = temp[3];        \
  355.     }
  356.  
  357. #define EXPANDBOUNDS(a)                        \
  358.     if (firstTime)                        \
  359.     {                            \
  360.         firstTime = false;                    \
  361.         if (IsArray(a))                    \
  362.         {                            \
  363.             Array2CArray(boundsElements, (a));        \
  364.         }                            \
  365.         else if (IsArray(myBounds))                \
  366.         {                            \
  367.             Array2CArray(boundsElements, (myBounds));    \
  368.         }                            \
  369.         else return (a);                    \
  370.     }                            \
  371.     else                            \
  372.     {                            \
  373.         real temp[4];                    \
  374.         if (IsArray(a))                    \
  375.         {                            \
  376.             Array2CArray(temp, (a));            \
  377.         }                            \
  378.         else if (IsArray(myBounds))                \
  379.         {                            \
  380.             Array2CArray(temp, (myBounds));            \
  381.         }                            \
  382.         else return (a);                    \
  383.         if (temp[0] < boundsElements[0])            \
  384.             boundsElements[0] = temp[0];        \
  385.         if (temp[1] > boundsElements[1])            \
  386.             boundsElements[1] = temp[1];        \
  387.         if (temp[2] < boundsElements[2])            \
  388.             boundsElements[2] = temp[2];        \
  389.         if (temp[3] > boundsElements[3])            \
  390.             boundsElements[3] = temp[3];        \
  391.     }
  392.  
  393. ObjPtr FieldBoundsInvalid(object, changeCount)
  394. ObjPtr object;
  395. unsigned long changeCount;
  396. /*For an object, tests to see if it needs drawing.  Returns
  397.   NULLOBJ    if it does not
  398.   array[4]    giving bounds if it does
  399.   ObjTrue    it it needs to be redrawn but does not know where
  400.  
  401.   Contents are assumed to be shifted in their space
  402. */
  403. {
  404.     ObjPtr test;
  405.     ObjPtr contents;
  406.     real boundsElements[4];
  407.     real myBoundsElements[4];
  408.     ObjPtr myBounds;
  409.     ObjPtr scrollBar;
  410.     Bool firstTime = true;
  411.     Bool fromTop = false;
  412.     int fieldDepth = 0;
  413.     int xOff, yOff;
  414.  
  415.     MakeVar(object, APPEARANCE);
  416.     MakeVar(object, BOUNDS);
  417.     fromTop = GetPredicate(object, TOPDOWN);
  418.  
  419.     myBounds = GetVar(object, BOUNDS);
  420.     if (IsArray(myBounds))
  421.     {
  422.     Array2CArray(myBoundsElements, myBounds);
  423.     }
  424.  
  425.     GETSCROLL(object, xOff, yOff);
  426.     if (GetPredicate(object, BORDERTYPE))
  427.     {
  428.     fieldDepth = 1;
  429.     }
  430.     else
  431.     {
  432.     fieldDepth = EDGE;
  433.     }
  434.  
  435.     MakeVar(object, CHANGEDBOUNDS);
  436.     if (GetVarChangeCount(object, CHANGEDBOUNDS) > changeCount)
  437.     {
  438.     /*Object is not good, so return the bounds*/
  439.  
  440.     test = GetVar(object, CHANGEDBOUNDS);
  441.  
  442.     if (test && IsArray(test) && RANK(test) == 1
  443.         && DIMS(test)[0] == 4)
  444.     {
  445.         EXPANDBOUNDS(test);
  446.     }
  447.     else
  448.     {
  449.         return ObjTrue;
  450.     }
  451.     }
  452.  
  453.     MakeVar(object, CONTENTS);
  454.     contents = GetVar(object, CONTENTS);
  455.     if (contents && IsList(contents))
  456.     {
  457.     /*Still, maybe some of the contents need to be drawn*/
  458.      ThingListPtr runner;
  459.  
  460.     runner = LISTOF(contents);
  461.     while (runner)
  462.     {
  463.         test = BoundsInvalid(runner -> thing, changeCount);
  464.         if (test)
  465.         {
  466.         EXPANDSHIFTEDBOUNDS(test);
  467.         }
  468.         runner = runner -> next;
  469.     }
  470.     }
  471.  
  472.     scrollBar = GetVar(object, HSCROLL);
  473.     if (scrollBar);
  474.     {
  475.     test = BoundsInvalid(scrollBar, changeCount);
  476.     if (test)
  477.     {
  478.         EXPANDBOUNDS(test);
  479.     }
  480.     }
  481.  
  482.     scrollBar = GetVar(object, VSCROLL);
  483.     if (scrollBar);
  484.     {
  485.     test = BoundsInvalid(scrollBar, changeCount);
  486.     if (test)
  487.     {
  488.         EXPANDBOUNDS(test);
  489.     }
  490.     }
  491.  
  492.     if (firstTime)
  493.     {
  494.     return NULLOBJ;
  495.     }
  496.     else
  497.     {
  498.     ObjPtr retVal;
  499.     retVal = NewRealArray(1, 4L);
  500.     CArray2Array(retVal, boundsElements);
  501.     return retVal;
  502.     }
  503. }
  504.  
  505. #ifdef GRAPHICS
  506. static ObjPtr DrawPanel(object)
  507. ObjPtr object;
  508. /*Draws a control panel*/
  509. {
  510.     int l, r, b, t;
  511.     ObjPtr backColor, borderType;
  512.  
  513.     Get2DIntBounds(object, &l, &r, &b, &t);
  514.     if (IsDrawingRestricted(l, r, b, t)) return ObjFalse;
  515.  
  516.     /*Setup the new panel area*/
  517.     StartPanel(l, r, b, t);
  518.  
  519.     /*Get the color, if any, and draw it*/
  520.     backColor = GetVar(object, BACKGROUND);
  521.     if (backColor)
  522.     {
  523.     if (GetPredicate(object, BACKNOTNEEDED))
  524.     {
  525.     }
  526.     else
  527.     {
  528.         SetObjectColor(backColor);
  529.         FillRect(0, r - l, 0, t - b);
  530.  
  531.         /*Kludge for IBM and Reality Engine*/
  532.         FrameRect(0, r - l, 0, t - b);
  533.     }
  534.     }
  535.     SetVar(object, BACKNOTNEEDED, ObjFalse);
  536.  
  537.     borderType = GetVar(object, BORDERTYPE);
  538.     if (borderType)
  539.     {
  540.     FrameUIRect(0, r - l - 1, 0, t - b - 1, UIBLACK);
  541.     }
  542.  
  543.     /*Draw the contents of the panel*/
  544.     DrawList(GetVar(object, CONTENTS));
  545.     StopPanel();
  546.  
  547.     return NULLOBJ;
  548. }
  549. #endif
  550.  
  551. static ObjPtr FindObjectField(object, name)
  552. ObjPtr object;
  553. char *name;
  554. /*Searches a field and its contents for an object with name*/
  555. {
  556.     ObjPtr retVal = NULLOBJ;
  557.     ObjPtr objName, contents;
  558.     ObjPtr scrollBar;
  559.     /*First check to see if I am the object*/
  560.     objName = GetVar(object, NAME);
  561.     if (objName && IsString(objName) && ObjectNameMatches(name, GetString(objName)))
  562.     {
  563.     if (!retVal)
  564.     {
  565.         retVal = NewList();
  566.     }
  567.     PostfixList(retVal, object);
  568.     }
  569.  
  570.     /*Now check my CONTENTS*/
  571.     contents = GetVar(object, CONTENTS);
  572.     if (contents)
  573.     {
  574.     ObjPtr foundObjects;
  575.     foundObjects = FindNamedObject(contents, name);
  576.     if (foundObjects)
  577.     {
  578.         if (!retVal)
  579.         {
  580.         retVal = NewList();
  581.         }
  582.         AppendList(retVal, foundObjects);
  583.     }
  584.     }
  585.  
  586.     /*Now check the scroll bars*/
  587.     scrollBar = GetVar(object, HSCROLL);
  588.     if (scrollBar)
  589.     {
  590.     objName = GetVar(scrollBar, NAME);
  591.     if (objName && IsString(objName) && 0 == strcmp2(GetString(objName), name))
  592.     {
  593.         if (!retVal)
  594.         {
  595.         retVal = NewList();
  596.         }
  597.         PostfixList(retVal, scrollBar);
  598.     }
  599.     }
  600.     scrollBar = GetVar(object, VSCROLL);
  601.     if (scrollBar)
  602.     {
  603.     objName = GetVar(scrollBar, NAME);
  604.     if (objName && IsString(objName) && 0 == strcmp2(GetString(objName), name))
  605.     {
  606.         if (!retVal)
  607.         {
  608.         retVal = NewList();
  609.         }
  610.         PostfixList(retVal, scrollBar);
  611.     }
  612.     }
  613.  
  614.     return retVal;
  615. }
  616.  
  617. static ObjPtr ForAllFieldObjects(object, routine)
  618. ObjPtr object;
  619. FuncTyp routine;
  620. /*Does routine on a field and its contents*/
  621. {
  622.     ObjPtr contents;
  623.     ObjPtr scrollBar;
  624.  
  625.     (*routine)(object);
  626.  
  627.     /*Now check my CONTENTS*/
  628.     contents = GetVar(object, CONTENTS);
  629.     if (contents)
  630.     {
  631.     ForAllObjects(contents, routine);
  632.     }
  633.  
  634.     /*Now check the scroll bars*/
  635.     scrollBar = GetVar(object, HSCROLL);
  636.     if (scrollBar)
  637.     {
  638.     ForAllObjects(scrollBar, routine);
  639.     }
  640.     scrollBar = GetVar(object, VSCROLL);
  641.     if (scrollBar)
  642.     {
  643.     ForAllObjects(scrollBar, routine);
  644.     }
  645.  
  646.     return ObjTrue;
  647. }
  648.  
  649. static Bool IconConflict(icons, x, y)
  650. ObjPtr icons;
  651. int x, y;
  652. /*See if the position conflicts with any of the icons*/ 
  653. {
  654.     ObjPtr locArray;
  655.     real loc[2];
  656.  
  657.     if (IsList(icons))
  658.     {
  659.     ThingListPtr list;
  660.     list = LISTOF(icons);
  661.     while (list)
  662.     {
  663.         locArray = GetFixedArrayVar("IconConflict", list -> thing, ICONLOC, 1, 2L);
  664.         if (!locArray)
  665.         {
  666.         return false;
  667.         }
  668.         Array2CArray(loc, locArray);
  669.  
  670.         if (ABS(x - loc[0]) < ICONXMINSPACE && ABS(y - loc[1]) < ICONYMINSPACE)
  671.         {
  672.         return true;
  673.         }
  674.         list = list -> next;
  675.     }
  676.     }
  677.     return false;
  678. }
  679.  
  680. #ifdef PROTO
  681. void DropIconInCorral(ObjPtr corral, ObjPtr icon)
  682. #else
  683. void DropIconInCorral(corral, icon)
  684. ObjPtr corral, icon;
  685. #endif
  686. /*Drops icon in corral, if ICONLOC is null, trying to find a place for it to 
  687.   fit.*/
  688. {
  689.     int x, y;            /*Trial icon spacing*/
  690.     int left, right, bottom, top;
  691.     int xmin, xmax;
  692.     ObjPtr contents;
  693.     ObjPtr locArray;
  694.     real loc[2];
  695.     char newName[256];        /*Trial new name*/
  696.     int k;
  697.     ObjPtr name;
  698.     Bool stagger;
  699.     Bool fromTop;
  700.  
  701.     fromTop = GetPredicate(corral, TOPDOWN);
  702.  
  703.     name = GetStringVar("DropIconInCorral", icon, NAME);
  704.     if (name)
  705.     {
  706.     /*Create a new name*/
  707.     for (k = 1; ; ++k)
  708.     {
  709.         strncpy(newName, GetString(name), 255);
  710.         newName[255] = 0;
  711.         if (k > 1)
  712.         {
  713.         sprintf(tempStr, " (%d)", k);
  714.         strcat(newName, tempStr);
  715.         }
  716.         if (FindNamedObject(corral, newName))
  717.         {
  718.         continue;
  719.         }
  720.         break;
  721.     }
  722.     SetVar(icon, NAME, NewString(newName));
  723.     }
  724.  
  725.     Get2DIntBounds(corral, &left, &right, &bottom, &top);
  726.  
  727.     contents = GetListVar("DropIconInCorral", corral, CONTENTS);
  728.     if (!contents)
  729.     {
  730.     return;
  731.     }
  732.  
  733.     if (GetVar(icon, ICONLOC) == NULLOBJ)
  734.     {
  735.     /*Calculate a location*/
  736.  
  737.     if (GetPredicate(corral, SINGLECORRAL))
  738.     {
  739.         x = (right - left) / 2;
  740.         y = GetPredicate(corral, TOPDOWN) ?
  741.         (bottom - top) / 2 + 25 :
  742.         (top - bottom) / 2 + 25;
  743.     }
  744.     else
  745.     {
  746.     stagger = GetPrefTruth(PREF_STAGGERICONS);
  747.     xmin = ICONLEFTBORDER;
  748.     xmax = right - left - ICONLEFTBORDER;
  749.     if (xmax < xmin) xmax = xmin;
  750.     for (y = fromTop ? - ICONTOPBORDER : ICONBOTBORDER; ; 
  751.             y += fromTop ? -ICONYSPACE : ICONYSPACE)
  752.     {
  753.         k = 0;
  754.         for (x = xmin; x <= xmax; x += ICONXSPACE)
  755.         {
  756.         int tempY;
  757.         tempY = ((k & 1) && stagger) ? (y + (fromTop ? -ICONYSPACE / 2 : ICONYSPACE / 2)) : y;
  758.         if (!IconConflict(contents, x, tempY))
  759.         {
  760.             y = tempY;
  761.             goto getoutahere;
  762.         }
  763.         ++k;
  764.         }
  765.     }
  766.     }
  767. getoutahere:
  768.     loc[0] = x;
  769.     loc[1] = y;
  770.     locArray = NewRealArray(1, (long) 2);
  771.     CArray2Array(locArray, loc);
  772.     SetVar(icon, ICONLOC, locArray);
  773.     }
  774.  
  775.     PostfixList(contents, icon);
  776.     SetVar(icon, PARENT, corral);
  777.     RecalcScroll(corral);
  778.     ImInvalid(corral);
  779.     return;
  780. }
  781.  
  782. #ifdef PROTO
  783. void DropIconSeriesInCorral(ObjPtr corral, ObjPtr icon)
  784. #else
  785. void DropIconSeriesInCorral(corral, icon)
  786. ObjPtr corral, icon;
  787. #endif
  788. /*Drops icon, which is one of a series, in corral.  If ICONLOC is null, 
  789.   will wait until next redraw and then find a connected block for all the
  790.   icons.
  791. */
  792. {
  793.     int x, y;            /*Trial icon spacing*/
  794.     int left, right, bottom, top;
  795.     int xmin, xmax;
  796.     ObjPtr contents;
  797.     ObjPtr locArray;
  798.     real loc[2];
  799.     char newName[256];        /*Trial new name*/
  800.     int k;
  801.     ObjPtr name;
  802.     Bool stagger;
  803.     Bool fromTop;
  804.  
  805.     fromTop = GetPredicate(corral, TOPDOWN);
  806.  
  807.     name = GetStringVar("DropIconInCorral", icon, NAME);
  808.     if (name)
  809.     {
  810.     /*Create a new name*/
  811.     for (k = 1; ; ++k)
  812.     {
  813.         strncpy(newName, GetString(name), 255);
  814.         newName[255] = 0;
  815.         if (k > 1)
  816.         {
  817.         sprintf(tempStr, " (%d)", k);
  818.         strcat(newName, tempStr);
  819.         }
  820.         if (FindNamedObject(corral, newName))
  821.         {
  822.         continue;
  823.         }
  824.         break;
  825.     }
  826.     SetVar(icon, NAME, NewString(newName));
  827.     }
  828.  
  829.     Get2DIntBounds(corral, &left, &right, &bottom, &top);
  830.  
  831.     contents = GetListVar("DropIconInCorral", corral, CONTENTS);
  832.     if (!contents)
  833.     {
  834.     return;
  835.     }
  836.  
  837.     PostfixList(contents, icon);
  838.     SetVar(icon, PARENT, corral);
  839.  
  840.     ImInvalid(corral);
  841.     return;
  842. }
  843.  
  844. #ifdef INTERACTIVE
  845. void SetScreenGrid(object)
  846. ObjPtr object;
  847. /*Sets the screen grid to a grid within object*/
  848. {
  849.     int l, r, b, t;
  850.     real gridSize;
  851.  
  852.     Get2DIntBounds(object, &l, &r, &b, &t);
  853.     xGrid = yGrid = ((real) (t - b)) / ((real) NGRIDSTEPS);
  854.     xMid = (r - l) * 0.5;
  855.     yMid = (t - b) * 0.5;
  856. }
  857. #endif
  858.  
  859. #ifdef GODLIKE
  860. static ObjPtr globalEditPanel;
  861. static ObjPtr globalEditObject;
  862.  
  863. #ifdef PROTO
  864. int ClosestGravity(ObjPtr object, int coord, Bool vertical, int min, int max)
  865. #else
  866. int ClosestGravity(object, coord, vertical, min, max)
  867. ObjPtr object;
  868. int coord;
  869. Bool vertical;
  870. int min, max;
  871. #endif
  872. /*Returns closest gravity snap.  vertical true if coord is vertical.
  873.   Returns -1 if none are valid*/
  874. {
  875.     int closest = -1;
  876.  
  877.     if (object == globalEditObject) return closest;
  878.  
  879.     if (IsList(object))
  880.     {
  881.     ThingListPtr runner;
  882.     runner = LISTOF(object);
  883.     while (runner)
  884.     {
  885.         int closer;
  886.  
  887.         closer = ClosestGravity(runner -> thing, coord, vertical, min, max);
  888.         if (closer >= 0 && ABS(closer - coord) < ABS(closest - coord))
  889.         {
  890.         closest = closer;
  891.         }
  892.         runner = runner -> next;
  893.     }
  894.     }
  895.     else
  896.     {
  897.     ObjPtr contents;
  898.     ObjPtr bounds;
  899.  
  900.     contents = GetVar(object, CONTENTS);
  901.     if (contents)
  902.     {
  903.         int closer;
  904.  
  905.         closer = ClosestGravity(contents, coord, vertical, min, max);
  906.         if (closer >= 0 && ABS(closer - coord) < ABS(closest - coord))
  907.         {
  908.         closest = closer;
  909.         }
  910.     }
  911.  
  912.     bounds = GetVar(object, BOUNDS);
  913.     if (bounds)
  914.     {
  915.         int l, r, b, t, closer;
  916.         Get2DIntBounds(object, &l, &r, &b, &t);
  917.  
  918.         /*For now, just snap to minorborder snaps*/
  919.  
  920.         if (vertical)
  921.         {
  922.         if (b <= max && t >= min)
  923.         {
  924.         closer = l - MINORBORDER;
  925.         if (ABS(closer - coord) < ABS(closest - coord))
  926.         {
  927.             closest = closer;
  928.         }
  929.         closer = l + MINORBORDER;
  930.         if (ABS(closer - coord) < ABS(closest - coord))
  931.         {
  932.             closest = closer;
  933.         }
  934.         closer = r - MINORBORDER;
  935.         if (ABS(closer - coord) < ABS(closest - coord))
  936.         {
  937.             closest = closer;
  938.         }
  939.         closer = r + MINORBORDER;
  940.         if (ABS(closer - coord) < ABS(closest - coord))
  941.         {
  942.             closest = closer;
  943.         }
  944.         closer = l - MAJORBORDER;
  945.         if (ABS(closer - coord) < ABS(closest - coord))
  946.         {
  947.             closest = closer;
  948.         }
  949.         closer = l + MAJORBORDER;
  950.         if (ABS(closer - coord) < ABS(closest - coord))
  951.         {
  952.             closest = closer;
  953.         }
  954.         closer = r - MAJORBORDER;
  955.         if (ABS(closer - coord) < ABS(closest - coord))
  956.         {
  957.             closest = closer;
  958.         }
  959.         closer = r + MAJORBORDER;
  960.         if (ABS(closer - coord) < ABS(closest - coord))
  961.         {
  962.             closest = closer;
  963.         }
  964.         }
  965.         }
  966.         else if (l <= max && r >= min)
  967.         {
  968.         ObjPtr ts;
  969.         closer = t - MINORBORDER;
  970.         if (ABS(closer - coord) < ABS(closest - coord))
  971.         {
  972.             closest = closer;
  973.         }
  974.         closer = t + MINORBORDER;
  975.         if (ABS(closer - coord) < ABS(closest - coord))
  976.         {
  977.             closest = closer;
  978.         }
  979.         closer = b - MINORBORDER;
  980.         if (ABS(closer - coord) < ABS(closest - coord))
  981.         {
  982.             closest = closer;
  983.         }
  984.         closer = b + MINORBORDER;
  985.         if (ABS(closer - coord) < ABS(closest - coord))
  986.         {
  987.             closest = closer;
  988.         }
  989.         closer = t - MAJORBORDER;
  990.         if (ABS(closer - coord) < ABS(closest - coord))
  991.         {
  992.             closest = closer;
  993.         }
  994.         closer = t + MAJORBORDER;
  995.         if (ABS(closer - coord) < ABS(closest - coord))
  996.         {
  997.             closest = closer;
  998.         }
  999.         closer = b - MAJORBORDER;
  1000.         if (ABS(closer - coord) < ABS(closest - coord))
  1001.         {
  1002.             closest = closer;
  1003.         }
  1004.         closer = b + MAJORBORDER;
  1005.         if (ABS(closer - coord) < ABS(closest - coord))
  1006.         {
  1007.             closest = closer;
  1008.         }
  1009.         /*Text box*/
  1010.         if ((ts = GetVar(globalEditObject, TYPESTRING)) &&
  1011.             (0 == strcmp2(GetString(ts), "text box")))
  1012.         {
  1013.             closer = b - TEXTBOXSEP;
  1014.             if (ABS(closer - coord) < ABS(closest - coord))
  1015.             {
  1016.             closest = closer;
  1017.             }
  1018.         }
  1019.         /*Radio button*/
  1020.         if ((ts = GetVar(globalEditObject, TYPESTRING)) &&
  1021.             (0 == strcmp2(GetString(ts), "radio button")))
  1022.         {
  1023.             closer = b - CHECKBOXSPACING;
  1024.             if (ABS(closer - coord) < ABS(closest - coord))
  1025.             {
  1026.             closest = closer;
  1027.             }
  1028.         }
  1029.         }
  1030.     }
  1031.     }
  1032.     return closest;
  1033. }
  1034.  
  1035. static ObjPtr PressEditBounds(object, x, y, flags)
  1036. ObjPtr object;
  1037. int x, y;
  1038. long flags;
  1039. /*Presses in an object for bounds editing*/
  1040. {
  1041.     ThingListPtr runner;
  1042.  
  1043.     if (IsList(object))
  1044.     {
  1045.     runner = LISTOF(object);
  1046.     while (runner)
  1047.     {
  1048.         ObjPtr retVal;
  1049.         retVal = PressEditBounds(runner -> thing, x, y, flags);
  1050.         if (IsTrue(retVal))
  1051.         {
  1052.         return retVal;
  1053.         }
  1054.         runner = runner -> next;
  1055.     }
  1056.     return ObjFalse;
  1057.     }
  1058.     else
  1059.     {
  1060.         real ob[4];
  1061.         ObjPtr boundsArray;
  1062.     ObjPtr contents;
  1063.         /*It's a magic drag*/
  1064.  
  1065.     contents = GetVar(object, CONTENTS);
  1066.     if (contents)
  1067.     {
  1068.         ObjPtr retVal;
  1069.         retVal = PressEditBounds(contents, x, y, flags);
  1070.         if (IsTrue(retVal))
  1071.         {
  1072.         return retVal;
  1073.         }
  1074.     }
  1075.  
  1076.         boundsArray = GetVar(object, BOUNDS);
  1077.     if (boundsArray)
  1078.     {
  1079.         Array2CArray(ob, boundsArray);
  1080.         if (x >= ob[0] && x <= ob[1] &&
  1081.         y >= ob[2] && y <= ob[3])
  1082.         {
  1083.         /*Click here!*/
  1084.         int initX, initY;
  1085.         Bool ml, mr, mb, mt;
  1086.         real newBounds[4];
  1087.         real oldNewBounds[4];
  1088.  
  1089.         if (flags & F_OPTIONDOWN)
  1090.         {
  1091.             ObjPtr parent, contents;
  1092.             parent = GetVar(object, PARENT);
  1093.             contents = GetVar(parent, CONTENTS);
  1094.             DeleteFromList(contents, object);
  1095.             PostfixList(contents, object);
  1096.         }
  1097.  
  1098.         newBounds[0] = oldNewBounds[0] = ob[0];
  1099.         newBounds[1] = oldNewBounds[1] = ob[1];
  1100.         newBounds[2] = oldNewBounds[2] = ob[2];
  1101.         newBounds[3] = oldNewBounds[3] = ob[3];
  1102.  
  1103.         initX = x;
  1104.         initY = y;
  1105.  
  1106.         /*Determine bits to move based on position*/
  1107.         mr = x >= ob[0] + 0.75 * (ob[1] - ob[0]);
  1108.         ml = x <= ob[0] + 0.25 * (ob[1] - ob[0]);
  1109.         mt = y >= ob[2] + 0.75 * (ob[3] - ob[2]);
  1110.         mb = y <= ob[2] + 0.25 * (ob[3] - ob[2]);
  1111.  
  1112.         if (!(mr | ml | mb | mt))
  1113.         {
  1114.             mr = ml = mb = mt = true;
  1115.         }
  1116.         while (Mouse(&x, &y))
  1117.         {
  1118.             if (x != initX || y != initY)
  1119.             {
  1120.             /*The mouse has moved*/
  1121.             ImInvalid(object);
  1122.  
  1123.             if (ml) newBounds[0] = ob[0] + x - initX;
  1124.             if (mr) newBounds[1] = ob[1] + x - initX;
  1125.             if (mb) newBounds[2] = ob[2] + y - initY;
  1126.             if (mt) newBounds[3] = ob[3] + y - initY;
  1127.  
  1128.             if (flags & F_SHIFTDOWN)
  1129.             {
  1130.                 /*Gravity drag*/
  1131.                 globalEditObject = object;
  1132.                 if (ml && mr && mb && mt)
  1133.                 {
  1134.                 int closest1, closest2, w, h;
  1135.                 /*Special case, maintain size*/
  1136.  
  1137.                 w = newBounds[1] - newBounds[0];
  1138.                 h = newBounds[3] - newBounds[2];
  1139.                 closest1 = ClosestGravity(globalEditPanel,
  1140.                         (int) newBounds[0], true,
  1141.                         (int) newBounds[2], (int) newBounds[3]);
  1142.                 
  1143.                 closest2 = ClosestGravity(globalEditPanel,
  1144.                         (int) newBounds[1], true,
  1145.                         (int) newBounds[2], (int) newBounds[3]);
  1146.  
  1147.                 if (closest1 >= 0 && ABS(closest1 - (int) newBounds[0]) <= EDITGRAVITY &&
  1148.                     closest2 >= 0 && ABS(closest2 - (int) newBounds[1]) <= EDITGRAVITY)
  1149.                 {
  1150.                     if (ABS(closest1 - (int) newBounds[0]) <
  1151.                     ABS(closest2 - (int) newBounds[1]))
  1152.                     {
  1153.                     newBounds[0] = closest1;
  1154.                     newBounds[1] = closest1 + w;
  1155.                     }
  1156.                     else
  1157.                     {
  1158.                     newBounds[1] = closest2;
  1159.                     newBounds[0] = closest2 - w;
  1160.                     }
  1161.                 }
  1162.                 else if (closest1 >= 0 && ABS(closest1 - (int) newBounds[0]) <= EDITGRAVITY)
  1163.                 {
  1164.                     newBounds[0] = closest1;
  1165.                     newBounds[1] = closest1 + w;
  1166.                 }
  1167.                 else if (closest2 >= 0 && ABS(closest2 - (int) newBounds[1]) <= EDITGRAVITY)
  1168.                 {
  1169.                     newBounds[1] = closest2;
  1170.                     newBounds[0] = closest2 - w;
  1171.                 }
  1172.  
  1173.                 closest1 = ClosestGravity(globalEditPanel,
  1174.                         (int) newBounds[2], false,
  1175.                         (int) newBounds[0], (int) newBounds[1]);
  1176.                 
  1177.                 closest2 = ClosestGravity(globalEditPanel,
  1178.                         (int) newBounds[3], false,
  1179.                         (int) newBounds[0], (int) newBounds[1]);
  1180.  
  1181.                 if (closest1 >= 0 && ABS(closest1 - (int) newBounds[2]) <= EDITGRAVITY &&
  1182.                     closest2 >= 0 && ABS(closest2 - (int) newBounds[3]) <= EDITGRAVITY)
  1183.                 {
  1184.                     if (ABS(closest1 - (int) newBounds[2]) <
  1185.                     ABS(closest2 - (int) newBounds[3]))
  1186.                     {
  1187.                     newBounds[2] = closest1;
  1188.                     newBounds[3] = closest1 + h;
  1189.                     }
  1190.                     else
  1191.                     {
  1192.                     newBounds[3] = closest2;
  1193.                     newBounds[2] = closest2 - h;
  1194.                     }
  1195.                 }
  1196.                 else if (closest1 >= 0 && ABS(closest1 - (int) newBounds[2]) <= EDITGRAVITY)
  1197.                 {
  1198.                     newBounds[2] = closest1;
  1199.                     newBounds[3] = closest1 + h;
  1200.                 }
  1201.                 else if (closest2 >= 0 && ABS(closest2 - (int) newBounds[3]) <= EDITGRAVITY)
  1202.                 {
  1203.                     newBounds[3] = closest2;
  1204.                     newBounds[2] = closest2 - h;
  1205.                 }
  1206.                 }
  1207.                 else
  1208.                 {
  1209.                 int closest;
  1210.  
  1211.                 if (ml)
  1212.                 {
  1213.                     closest = ClosestGravity(globalEditPanel,
  1214.                         (int) newBounds[0], true,
  1215.                         (int) newBounds[2], (int) newBounds[3]);
  1216.                     if (closest >= 0 && ABS(closest - (int) newBounds[0]) <= EDITGRAVITY) newBounds[0] = closest;
  1217.                 }
  1218.  
  1219.                 if (mr)
  1220.                 {
  1221.                     closest = ClosestGravity(globalEditPanel,
  1222.                         (int) newBounds[1], true,
  1223.                         (int) newBounds[2], (int) newBounds[3]);
  1224.                     if (closest >= 0 && ABS(closest - (int) newBounds[1]) <= EDITGRAVITY) newBounds[1] = closest;
  1225.                 }
  1226.                 
  1227.                 if (mb)
  1228.                 {
  1229.                     closest = ClosestGravity(globalEditPanel,
  1230.                         (int) newBounds[2], false,
  1231.                         (int) newBounds[0], (int) newBounds[1]);
  1232.                     if (closest >= 0 && ABS(closest - (int) newBounds[2]) <= EDITGRAVITY) newBounds[2] = closest;
  1233.                 }
  1234.  
  1235.                 if (mt)
  1236.                 {
  1237.                     closest = ClosestGravity(globalEditPanel,
  1238.                         (int) newBounds[3], false,
  1239.                         (int) newBounds[0], (int) newBounds[1]);
  1240.                     if (closest >= 0 && ABS(closest - (int) newBounds[3]) <= EDITGRAVITY) newBounds[3] = closest;
  1241.                 }
  1242.                 }
  1243.             }
  1244.  
  1245.             if ((newBounds[0] != oldNewBounds[0] ||
  1246.                  newBounds[1] != oldNewBounds[1] ||
  1247.                  newBounds[2] != oldNewBounds[2] ||
  1248.                  newBounds[3] != oldNewBounds[3]) &&
  1249.                  newBounds[0] < newBounds[1] &&
  1250.                  newBounds[2] < newBounds[3])
  1251.             {
  1252.                 boundsArray = NewRealArray(1, 4L);
  1253.                 CArray2Array(boundsArray, newBounds);
  1254.                 SetVar(object, BOUNDS, boundsArray);
  1255.                 oldNewBounds[0] = newBounds[0];
  1256.                 oldNewBounds[1] = newBounds[1];
  1257.                 oldNewBounds[2] = newBounds[2];
  1258.                 oldNewBounds[3] = newBounds[3];
  1259.                 DrawMe(object);
  1260.             }
  1261.             }
  1262.         }
  1263.         return ObjTrue;
  1264.         }
  1265.     }
  1266.     }
  1267.     return ObjFalse;
  1268. }
  1269. #endif
  1270.  
  1271. #ifdef INTERACTIVE
  1272. static ObjPtr PressPanel(object, x, y, flags)
  1273. ObjPtr object;
  1274. int x, y;
  1275. long flags;
  1276. /*Does a press in a panel beginning at x and y.  Returns
  1277.   true iff the press really was in the panel.*/
  1278. {
  1279.     int left, right, bottom, top;
  1280.  
  1281.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  1282.  
  1283.     SetScreenGrid(object);
  1284.  
  1285.     if (x >= left && x <= right && y >= bottom && y <= top)
  1286.     {
  1287.     /*Hey!  It really was a click in the panel*/
  1288.     ObjPtr contents;
  1289.     ObjPtr retVal;
  1290.  
  1291.     /*See if it's a dragBuffer click*/
  1292.     if (dragBuffer)
  1293.     {
  1294.         /*Yes it is.  Move dragBuffer and exit*/
  1295.         dropObject = dragBuffer;
  1296.         dragBuffer = NULLOBJ;
  1297.         return ObjTrue;
  1298.     }
  1299.  
  1300.         /*Setup the new panel area*/
  1301.     StartPanel(left, right, bottom, top);
  1302.  
  1303.         x -= left;
  1304.         y -= bottom;
  1305.     
  1306.         contents = GetVar(object, CONTENTS);
  1307.     if (contents && IsList(contents))
  1308.     {
  1309. #ifdef GODLIKE
  1310.         ObjPtr panel;
  1311.         if (GetPredicate(panel = GetVar(object, PARENT), SHOWBOUNDS))
  1312.         {
  1313.         globalEditPanel = panel;
  1314.         PressEditBounds(contents, x, y, flags);
  1315.         StopPanel();
  1316.         return ObjTrue;
  1317.         }
  1318.         else
  1319. #endif
  1320.         {
  1321.         /*It's a normal click*/
  1322.         retVal = PressObject(contents, x, y, flags);
  1323.         }
  1324.         if (TOOL(flags) == T_HELP && !IsTrue(retVal))
  1325.         {
  1326.         ContextHelp(object);
  1327.         }
  1328.     }
  1329.     else
  1330.     {
  1331.         retVal = ObjFalse;
  1332.     }
  1333.  
  1334.     StopPanel();
  1335.     return retVal;
  1336.     }
  1337.     else
  1338.     {
  1339.     return ObjFalse;
  1340.     }
  1341. }
  1342. #endif
  1343.  
  1344. #ifdef INTERACTIVE
  1345. static ObjPtr DropInPanel(object, dropObj, x, y)
  1346. ObjPtr object, dropObj;
  1347. int x, y;
  1348. /*Drops object in a panel beginning at x and y.  Returns
  1349.   true iff the drop really was in the panel.*/
  1350. {
  1351.     int left, right, bottom, top;
  1352.  
  1353.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  1354.  
  1355.     if (x >= left && x <= right && y >= bottom && y <= top)
  1356.     {
  1357.     /*Hey!  It really was a drop in the panel*/
  1358.     ObjPtr contents;
  1359.  
  1360.         /*Setup the new panel area*/
  1361.     StartPanel(left, right, bottom, top);
  1362.  
  1363.         x -= left;
  1364.         y -= bottom;
  1365.     contents = GetVar(object, CONTENTS);
  1366.     if (contents && IsList(contents))
  1367.     {
  1368.         DropList(contents, dropObj, x, y);
  1369.     }
  1370.  
  1371.     StopPanel();
  1372.     return ObjTrue;
  1373.     }
  1374.     else
  1375.     {
  1376.     return ObjFalse;
  1377.     }
  1378. }
  1379. #endif
  1380.  
  1381. #ifdef INTERACTIVE
  1382. static ObjPtr KeyDownContents(object, key, flags)
  1383. ObjPtr object;
  1384. int key;
  1385. long flags;
  1386. /*Does a keydown in something with a CONTENTS*/
  1387. {
  1388.     ObjPtr contents;
  1389.     contents = GetVar(object, CONTENTS);
  1390.     if (contents)
  1391.     {
  1392.     return KeyDownList(contents, key, flags);
  1393.     }
  1394.     else
  1395.     {
  1396.     return ObjFalse;
  1397.     }
  1398. }
  1399. #endif
  1400.  
  1401. #ifdef INTERACTIVE
  1402. static ObjPtr PressFieldContents(object, x, y, flags)
  1403. ObjPtr object;
  1404. int x, y;
  1405. long flags;
  1406. /*Presses the contents of a field*/
  1407. {
  1408.     ObjPtr contents;
  1409.  
  1410.     contents = GetListVar("PressFieldContents", object, CONTENTS);
  1411.     if (contents)
  1412.     {
  1413.     return PressObject(contents, x, y, flags);
  1414.     }
  1415.     else
  1416.     {
  1417.     return ObjFalse;
  1418.     }
  1419. }
  1420. #endif
  1421.  
  1422. void ScrollHome(field)
  1423. ObjPtr field;
  1424. /*Scrolls any field to home.*/
  1425. {
  1426.     ObjPtr scrollbar;
  1427.  
  1428.     scrollbar = GetVar(field, HSCROLL);
  1429.     if (scrollbar)
  1430.     {
  1431.     SetSliderValue(scrollbar, 0.0);
  1432.     }
  1433.  
  1434.     scrollbar = GetVar(field, VSCROLL);
  1435.     if (scrollbar)
  1436.     {
  1437.     SetSliderValue(scrollbar, 0.0);
  1438.     }
  1439. }
  1440.  
  1441. #ifdef INTERACTIVE
  1442. static ObjPtr PressField(object, x, y, flags)
  1443. ObjPtr object;
  1444. int x, y;
  1445. long flags;
  1446. /*Does a press in a field beginning at x and y.  Returns
  1447.   true iff the press really was in the field.*/
  1448. {
  1449.     int left, right, bottom, top;
  1450.     FuncTyp pressContents;        /*Routine to press the contents*/
  1451.     ObjPtr scrollBar;
  1452.  
  1453.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  1454.  
  1455.     /*See if it's a press in a scrollbar*/
  1456.     scrollBar = GetVar(object, HSCROLL);
  1457.     if (scrollBar)
  1458.     {
  1459.     if (IsTrue(PressObject(scrollBar, x, y, flags)))
  1460.     {
  1461.         return ObjTrue;
  1462.     }
  1463.     }
  1464.     scrollBar = GetVar(object, VSCROLL);
  1465.     if (scrollBar)
  1466.     {
  1467.     if (IsTrue(PressObject(scrollBar, x, y, flags)))
  1468.     {
  1469.         return ObjTrue;
  1470.     }
  1471.     }
  1472.  
  1473.     if (x >= left && x <= right && y >= bottom && y <= top)
  1474.     {
  1475.     /*Hey!  It really was a click in the field*/
  1476.     int xOff, yOff;
  1477.     ObjPtr contentsPressed = ObjFalse;
  1478.     int fieldDepth;
  1479.     if (GetPredicate(object, BORDERTYPE))
  1480.     {
  1481.         fieldDepth = 1;
  1482.     }
  1483.     else
  1484.     {
  1485.         fieldDepth = EDGE;
  1486.     }
  1487.  
  1488.     GETSCROLL(object, xOff, yOff);
  1489.  
  1490.     SetClipRect(left + fieldDepth, right - fieldDepth, bottom + fieldDepth, top - fieldDepth);
  1491.     if (GetPredicate(object, TOPDOWN))
  1492.     {
  1493.         SetOrigin(left + fieldDepth + xOff, top - fieldDepth + yOff);
  1494.             x -= left + fieldDepth + xOff;
  1495.             y -= top - fieldDepth + yOff;
  1496.     }
  1497.     else
  1498.     {
  1499.         SetOrigin(left + fieldDepth + xOff, bottom + fieldDepth + yOff);
  1500.             x -= left + fieldDepth + xOff;
  1501.             y -= bottom + fieldDepth + yOff;
  1502.     }
  1503.     
  1504.     pressContents = GetMethod(object, PRESSCONTENTS);
  1505.     if (pressContents)
  1506.     {
  1507.         contentsPressed = (*pressContents)(object, x, y, flags);
  1508.     }
  1509.     if (!IsTrue(contentsPressed))
  1510.     {
  1511.         if (TOOL(flags) == T_HELP)
  1512.         {
  1513.         ContextHelp(object);
  1514.         return ObjTrue;
  1515.         }
  1516.     }
  1517.  
  1518.     RestoreOrigin();
  1519.     RestoreClipRect();
  1520.     return ObjTrue;
  1521.     }
  1522.     else
  1523.     {
  1524.     return ObjFalse;
  1525.     }
  1526. }
  1527. #endif
  1528.  
  1529. #ifdef INTERACTIVE
  1530. static ObjPtr DropInCorral(object, dropObj, x, y)
  1531. ObjPtr object, dropObj;
  1532. int x, y;
  1533. /*Drops dropObj in corral object at x and y.  Returns
  1534.   true iff the drop really was in the corral.*/
  1535. {
  1536.     int left, right, bottom, top;
  1537.  
  1538.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  1539.  
  1540.     if (x >= left && x <= right && y >= bottom && y <= top)
  1541.     {
  1542.     /*Hey!  It really was a drop in the corral*/
  1543.     ObjPtr contents;
  1544.     int xOff, yOff;
  1545.     ObjPtr firstIcon;
  1546.     ThingListPtr restIcons;
  1547.     ThingListPtr runner;
  1548.     ObjPtr iconLoc;
  1549.     real loc[2];
  1550.     int xDisp, yDisp;
  1551.     int fieldDepth;
  1552.  
  1553.     if (GetPredicate(object, BORDERTYPE))
  1554.     {
  1555.         fieldDepth = 1;
  1556.     }
  1557.     else
  1558.     {
  1559.         fieldDepth = EDGE;
  1560.     }
  1561.  
  1562.     GETSCROLL(object, xOff, yOff);
  1563.  
  1564.     SetClipRect(left + fieldDepth, right - fieldDepth, bottom + fieldDepth, top - fieldDepth);
  1565.     if (GetPredicate(object, TOPDOWN))
  1566.     {
  1567.         SetOrigin(left + fieldDepth + xOff, top - fieldDepth + yOff);
  1568.         y -= top - fieldDepth + yOff;
  1569.     }
  1570.     else
  1571.     {
  1572.         SetOrigin(left + fieldDepth + xOff, bottom + fieldDepth + yOff);
  1573.         y -= bottom + fieldDepth + yOff;
  1574.     }
  1575.         x -= left + fieldDepth + xOff;
  1576.     x += iconXOff;
  1577.     y += iconYOff;
  1578.  
  1579.     /*Get the first icon and the rest of the icons*/
  1580.     if (IsList(dropObj))
  1581.     {
  1582.         restIcons = LISTOF(dropObj);
  1583.         firstIcon = restIcons -> thing;
  1584.         restIcons = restIcons -> next;
  1585.     }
  1586.     else if (IsIcon(dropObj))
  1587.     {
  1588.         firstIcon = dropObj;
  1589.         restIcons = 0;
  1590.     }
  1591.     else
  1592.     {
  1593.         ReportError("DropInCorral", "An object not an icon was dropped");
  1594.         return ObjFalse;
  1595.     }
  1596.  
  1597.     /*Get the location of the first icon*/
  1598.     iconLoc = GetFixedArrayVar("DropInCorral", firstIcon, ICONLOC, 1, 2L);
  1599.     if (!iconLoc)
  1600.     {
  1601.         return ObjFalse;
  1602.     }
  1603.     Array2CArray(loc, iconLoc);
  1604.     xDisp = x - loc[0];
  1605.     yDisp = y - loc[1];
  1606.  
  1607.     /*See if the first icon is already in the contents*/
  1608.     contents = GetVar(object, CONTENTS);
  1609.     if (contents && IsList(contents))
  1610.     {
  1611.         ThingListPtr list;
  1612.  
  1613.         list = LISTOF(contents);
  1614.         while (list)
  1615.         {
  1616.         if (list -> thing == firstIcon)
  1617.         {
  1618.             /*Hey, it's just a move*/
  1619.             real loc[2];
  1620.             ObjPtr array;
  1621.             loc[0] = x;
  1622.             loc[1] = y;
  1623.  
  1624.             array = NewRealArray(1, 2L);
  1625.             CArray2Array(array, loc);
  1626.             SetVar(firstIcon, ICONLOC, array);
  1627.  
  1628.             runner = restIcons;
  1629.             while (runner)
  1630.             {
  1631.             array = GetFixedArrayVar("DropInCorral", runner -> thing, ICONLOC, 1, 2L);
  1632.             if (!array) return ObjFalse;
  1633.             Array2CArray(loc, array);
  1634.             loc[0] += xDisp;
  1635.             loc[1] += yDisp;
  1636.             array = NewRealArray(1, 2L);
  1637.             CArray2Array(array, loc);
  1638.             SetVar(runner -> thing, ICONLOC, array);
  1639.             runner = runner -> next;
  1640.             }
  1641.  
  1642.             RecalcScroll(object);
  1643.             ImInvalid(object);
  1644.  
  1645.             break;
  1646.         }
  1647.         list = list -> next;
  1648.         }
  1649.         if (!list)
  1650.         {
  1651.         FuncTyp method;
  1652.         ObjPtr array;
  1653.         real loc[2];
  1654.         ObjPtr hScroll, vScroll;
  1655.         
  1656.         /*It must not have been already in the corral.  Give the
  1657.           corral a chance to act on it*/
  1658.         hScroll = GetVar(object, HSCROLL);
  1659.         vScroll = GetVar(object, VSCROLL);
  1660.         method = GetMethod(object, DROPINCONTENTS);
  1661.         if (method)
  1662.         {
  1663.             (*method)(object, firstIcon, x, y);
  1664.             runner = restIcons;
  1665.             while (runner)
  1666.             {
  1667.             array = GetFixedArrayVar("DropInCorral", runner -> thing, ICONLOC, 1, 2L);
  1668.             if (!array) return ObjFalse;
  1669.             Array2CArray(loc, array);
  1670.             loc[0] += xDisp;
  1671.             loc[1] += yDisp;
  1672.  
  1673.             /*Trim location to be inside corral*/
  1674.             if (!hScroll)
  1675.             {
  1676.                 if (loc[0] < left - EDGE) loc[0] = left - EDGE;
  1677.                 else if (loc[0] > right - EDGE) loc[0] = right - EDGE;
  1678.             }
  1679.             if (!vScroll)
  1680.             {
  1681.                 if (loc[1] < bottom - EDGE) loc[1] = bottom - EDGE;
  1682.                 else if (loc[1] > top - EDGE) loc[1] = top - EDGE;
  1683.             }
  1684.  
  1685.             (*method)(object, runner -> thing, (int) loc[0], (int) loc[1]);
  1686.             runner = runner -> next;
  1687.             }
  1688.             ImInvalid(object);
  1689.             RecalcScroll(object);
  1690.         }
  1691.         }
  1692.     }
  1693.     RestoreOrigin();
  1694.     RestoreClipRect();
  1695.  
  1696.     return ObjTrue;
  1697.     }
  1698.     else
  1699.     {
  1700.     return ObjFalse;
  1701.     }
  1702. }
  1703. #endif
  1704.  
  1705. #ifdef INTERACTIVE
  1706. Bool DragIcons(objects, x, y)
  1707. ObjPtr objects;
  1708. int x, y;
  1709. /*Drags an icon starting at x and y
  1710.   Returns true if it succeeded*/
  1711. {
  1712.     Bool dragging;        /*True iff dragging*/
  1713.     int xDisp, yDisp;        /*X and Y displacements from global to local*/
  1714.     int xOff, yOff;        /*X and Y offsets for drawing icon*/
  1715.     int newX, newY;
  1716.     int lastX, lastY;
  1717.     ThingListPtr runner;    /*A runner for the list*/
  1718.     ObjPtr firstIcon;        /*The first icon in the list*/
  1719.     ThingListPtr restIcons;    /*The list of the rest of the icons*/
  1720.     ObjPtr locArray;
  1721.     real loc[2];        /*Location of the first icon*/
  1722.  
  1723.     if (IsList(objects))
  1724.     {
  1725.     /*It's a list of icons.*/
  1726.     restIcons = LISTOF(objects);
  1727.     firstIcon = restIcons -> thing;
  1728.     restIcons = restIcons -> next;
  1729.     }
  1730.     else
  1731.     {
  1732.     /*It's a single icon, kludge it up so that it will continue to work*/
  1733.     firstIcon = objects;
  1734.     restIcons = 0;
  1735.     }
  1736.  
  1737.     CurOffset(&xDisp, &yDisp);
  1738.  
  1739.     locArray = GetFixedArrayVar("DragIcons", firstIcon, ICONLOC, 1, 2L);
  1740.     if (!locArray)
  1741.     {
  1742.     return;
  1743.     }
  1744.     Array2CArray(loc, locArray);
  1745.  
  1746.     /*Set relative offset for icon*/
  1747.     iconXOff = loc[0] - x;
  1748.     iconYOff = loc[1] - y;
  1749.  
  1750. #ifdef INTERWINDRAG
  1751.     xOff = xDisp;
  1752.     yOff = yDisp;
  1753. #else
  1754.     xOff = 0;
  1755.     yOff = 0;
  1756. #endif
  1757.     xOff -= x;
  1758.     yOff -= y;
  1759.  
  1760.     dragging = false;
  1761.     
  1762.     lastX = x;
  1763.     lastY = y;
  1764.     while (Mouse(&newX, &newY))
  1765.     {
  1766.     if (ABS(newX - x) > 2 || ABS(newY - y) > 2)
  1767.     {
  1768.         /*Start to drag*/
  1769.         dragging = true;
  1770.         pushattributes();
  1771. #ifdef INTERWINDRAG
  1772.         FullScreen(true);
  1773. #endif
  1774.         Mouse(&newX, &newY);
  1775.         OverDraw(true);
  1776.         SetUIColor(UIRED);
  1777.  
  1778.         DrawIconGhost(firstIcon, newX + xOff, newY + yOff);
  1779.         runner = restIcons;
  1780.         while (runner)
  1781.         {
  1782.         DrawIconGhost(runner -> thing, newX + xOff, newY + yOff);
  1783.         runner = runner -> next;
  1784.         }
  1785.         lastX = newX;
  1786.         lastY = newY;
  1787.         break;
  1788.     }
  1789.     }
  1790.  
  1791.     if (!dragging) return false;
  1792.     
  1793.     if (logging)
  1794.     {
  1795.     LogSelectedObjFunction(OF_PICK_UP);
  1796.     }
  1797.  
  1798.     while (Mouse(&newX, &newY))
  1799.     {
  1800.     if (newX != lastX || newY != lastY)
  1801.     {
  1802.         /*Erase, move, and redraw*/
  1803.         SetUIColor(UIBLACK);
  1804.         DrawIconGhost(firstIcon, lastX + xOff, lastY + yOff);
  1805.         runner = restIcons;
  1806.         while (runner)
  1807.         {
  1808.         DrawIconGhost(runner -> thing, lastX + xOff, lastY + yOff);
  1809.         runner = runner -> next;
  1810.         }
  1811.         SetUIColor(UIRED);
  1812.         DrawIconGhost(firstIcon, newX + xOff, newY + yOff);
  1813.         runner = restIcons;
  1814.         while (runner)
  1815.         {
  1816.         DrawIconGhost(runner -> thing, newX + xOff, newY + yOff);
  1817.         runner = runner -> next;
  1818.         }
  1819.  
  1820.         lastX = newX;
  1821.         lastY = newY;
  1822.     }
  1823.     }
  1824.     SetUIColor(UIBLACK);
  1825.     DrawIconGhost(firstIcon, lastX + xOff, lastY + yOff);
  1826.     runner = restIcons;
  1827.     while (runner)
  1828.     {
  1829.     DrawIconGhost(runner -> thing, lastX + xOff, lastY + yOff);
  1830.     runner = runner -> next;
  1831.     }
  1832.     if (overDraw)
  1833.     {
  1834.     EraseAll();
  1835.     OverDraw(false);
  1836.     }
  1837.     if (dragging)
  1838.     {
  1839. #ifdef INTERWINDRAG
  1840.     FullScreen(false);
  1841. #endif
  1842.     popattributes();
  1843.     }
  1844.     gconfig();
  1845.     Mouse(&dropX, &dropY);
  1846.     dropX += xDisp;
  1847.     dropY += yDisp;
  1848.     return true;
  1849. }
  1850. #endif
  1851.  
  1852. static ObjPtr SelectIcon(object)
  1853. ObjPtr object;
  1854. /*Selects an object if it's an icon and represents something.  Only works
  1855.   as a parameter to ForAllObjects*/
  1856. {
  1857.     if (IsIcon(object) && GetVar(object, REPOBJ) && !IsSelected(object))
  1858.     {
  1859.     Select(object, true);
  1860.     return ObjTrue;
  1861.     }
  1862.     else
  1863.     {
  1864.     return ObjFalse;
  1865.     }
  1866. }
  1867.  
  1868. void SelectAllIcons(window)
  1869. ObjPtr window;
  1870. /*Selects all icons in the window*/
  1871. {
  1872.     if (logging)
  1873.     {
  1874.     if (scriptSelectP)
  1875.     {
  1876.         Log("selectall\n");
  1877.     }
  1878.     InhibitLogging(true);
  1879.     }
  1880.     ForAllObjects(window, SelectIcon);
  1881.     if (logging)
  1882.     {
  1883.     InhibitLogging(false);
  1884.     }
  1885. }
  1886.  
  1887. static ObjPtr DeselectIcon(object)
  1888. ObjPtr object;
  1889. /*Deselects an object if it's an icon and represents something.  Only works
  1890.   as a parameter to ForAllObjects*/
  1891. {
  1892.     if (IsIcon(object) && GetVar(object, REPOBJ) && IsSelected(object))
  1893.     {
  1894.     Select(object, false);
  1895.     return ObjTrue;
  1896.     }
  1897.     else
  1898.     {
  1899.     return ObjFalse;
  1900.     }
  1901. }
  1902.  
  1903. void DeselectAll()
  1904. /*Deselects all the currently selected objects*/
  1905. {
  1906.     ThingListPtr runner, next;
  1907.     ObjPtr allSelected;
  1908.  
  1909.     if (scriptSelectP)
  1910.     {
  1911.     Log("deselectall\n");
  1912.     }
  1913.  
  1914.     allSelected = GetListVar("DeselectAll", objClass, ALLSELECTED);
  1915.     if (!allSelected) return;
  1916.  
  1917.     runner = LISTOF(allSelected);
  1918.  
  1919.     while (runner)
  1920.     {
  1921.     next = runner -> next;
  1922.     Select(runner -> thing, false);
  1923.     runner = next;
  1924.     }
  1925.     MakeMeCurrent(NULLOBJ);
  1926. }
  1927.  
  1928. void DoSelectAllIcons()
  1929. /*Selects all icons in the current window*/
  1930. {
  1931.     if (!selWinInfo)
  1932.     {
  1933.     return;
  1934.     }
  1935.     SelectAllIcons((ObjPtr) selWinInfo);
  1936. }
  1937.  
  1938. static Bool IsIconSelected(icon)
  1939. ObjPtr icon;
  1940. /*Returns true iff icon is selected*/
  1941. {
  1942.     ObjPtr repObj;
  1943.     repObj = GetVar(icon, REPOBJ);
  1944.     if (repObj) return IsSelected(repObj);
  1945.     else return IsSelected(icon);
  1946. }
  1947.  
  1948. #ifdef INTERACTIVE
  1949. static ObjPtr PressCorralContents(corral, x, y, flags)
  1950. ObjPtr corral;
  1951. int x, y;
  1952. long flags;
  1953. /*Does a press in the contents of a corral*/
  1954. {
  1955.     ObjPtr contents;
  1956.     ObjPtr pressedIcon = 0;    /*The icon pressed in*/
  1957.     ThingListPtr runner;
  1958.     FuncTyp method;
  1959.  
  1960.     contents = GetListVar("PressCorralContents", corral, CONTENTS);
  1961.     if (!contents) return ObjFalse;
  1962.  
  1963.     runner = LISTOF(contents);
  1964.     while (runner)
  1965.     {
  1966.         ObjPtr icon;
  1967.     ObjPtr theLoc;
  1968.     real loc[2];
  1969.  
  1970.     icon = runner -> thing;
  1971.     theLoc = GetFixedArrayVar("PressCorralContents", icon, ICONLOC, 1, 2L);
  1972.     if (theLoc)
  1973.     {
  1974.         Array2CArray(loc, theLoc);
  1975.  
  1976.         if (x >= ((int) loc[0]) - 16 && x <= ((int) loc[0]) + 16 && 
  1977.         y >= ((int) loc[1]) - 32 && y <= ((int) loc[1]) + 16)
  1978.         {
  1979.         pressedIcon = icon;
  1980.         }
  1981.      }
  1982.     runner = runner -> next;
  1983.     }
  1984.  
  1985.     if (pressedIcon)
  1986.     {
  1987.     Bool wasSelected;
  1988.  
  1989.     if (TOOL(flags) == T_HELP)
  1990.     {
  1991.         ContextHelp(pressedIcon);
  1992.         return ObjTrue;
  1993.     }
  1994.  
  1995.     wasSelected = IsIconSelected(pressedIcon);
  1996.  
  1997.     /*Something has been pressed.  
  1998.       Deselect all other objects IF
  1999.       1) It's a oneIcon field, or
  2000.       2) It's not a oneIcon field and
  2001.          the shift key is up and
  2002.          the icon was not previously selected*/
  2003.  
  2004.     if (!wasSelected &&
  2005.         (0 == (flags & F_SHIFTDOWN)) &&
  2006.         (TOOL(flags) != T_ROTATE) &&
  2007.         (0 == (flags & F_DOUBLECLICK)))
  2008.     {
  2009.         DeselectAll();
  2010.     }
  2011.  
  2012.     /*Select or deselect the icon*/
  2013.     if (wasSelected)
  2014.         {
  2015.         /*Already selected.  Only deselect if shift down*/
  2016.         if ((flags & F_SHIFTDOWN) || (TOOL(flags) == T_ROTATE))
  2017.         {
  2018.         Select(pressedIcon, false);
  2019.         pressedIcon = NULLOBJ;
  2020.         DrawMe(pressedIcon);
  2021.         }
  2022.     }
  2023.     else
  2024.     {
  2025.         Select(pressedIcon, true);
  2026.         DrawMe(pressedIcon);
  2027.     }
  2028.     }
  2029.     else
  2030.     {
  2031.     /*Start a marquee drag*/
  2032.     int newX, newY;
  2033.     int curX, curY;    
  2034.     ObjPtr marquee;
  2035.     real marqueeBounds[4];
  2036.     real oldMarqueeBounds[4];
  2037.     Bool yesMarquee = false;
  2038.     Bool firstTime = true;
  2039.  
  2040.     curX = x;
  2041.     curY = y;
  2042.     marqueeBounds[0] = marqueeBounds[1] = x;
  2043.     marqueeBounds[2] = marqueeBounds[3] = y;
  2044.  
  2045.     if (TOOL(flags) == T_HELP)
  2046.     {
  2047.         ContextHelp(corral);
  2048.         return ObjTrue;
  2049.     }
  2050.  
  2051.     /*Deselect all other icons if the shift key is not down*/
  2052.     if (0 == (flags & F_SHIFTDOWN) && TOOL(flags) != T_ROTATE)
  2053.     {
  2054.         DeselectAll();
  2055.         DrawMe(corral);
  2056.     }
  2057.     Mouse(&newX, &newY);
  2058.  
  2059.     if (nOverDrawPlanes)
  2060.     {
  2061.         OverDraw(true);
  2062.     }
  2063.     while (Mouse(&newX, &newY))
  2064.     {
  2065.         if (newX != curX || newY != curY)
  2066.         {
  2067.         yesMarquee = true;
  2068.         curX = newX;
  2069.         curY = newY;
  2070.         oldMarqueeBounds[0] = marqueeBounds[0];
  2071.         oldMarqueeBounds[1] = marqueeBounds[1];
  2072.         oldMarqueeBounds[2] = marqueeBounds[2];
  2073.         oldMarqueeBounds[3] = marqueeBounds[3];
  2074.         if (curX > x)
  2075.         {
  2076.             marqueeBounds[0] = x;
  2077.             marqueeBounds[1] = curX;
  2078.         }
  2079.         else if (x > curX)
  2080.         {
  2081.             marqueeBounds[0] = curX;
  2082.             marqueeBounds[1] = x;
  2083.         }
  2084.         else
  2085.         {
  2086.             yesMarquee = false;
  2087.         }
  2088.  
  2089.         if (curY > y)
  2090.         {
  2091.             marqueeBounds[2] = y;
  2092.             marqueeBounds[3] = curY;
  2093.         }
  2094.         else if (y > curY)
  2095.         {
  2096.             marqueeBounds[2] = curY;
  2097.             marqueeBounds[3] = y;
  2098.         }
  2099.         else
  2100.         {
  2101.             yesMarquee = false;
  2102.         }
  2103.         
  2104.         if (yesMarquee)
  2105.         {
  2106.             marquee = NewRealArray(1, 4L);
  2107.             CArray2Array(marquee, marqueeBounds);
  2108.         }
  2109.         else
  2110.         {
  2111.             marquee = NULLOBJ;
  2112.         }
  2113.  
  2114.         if (nOverDrawPlanes)
  2115.         {
  2116.             if (firstTime)
  2117.             {
  2118.             firstTime = false;
  2119.             }
  2120.             else
  2121.             {
  2122.             FrameUIRect(oldMarqueeBounds[0], oldMarqueeBounds[1],
  2123.                     oldMarqueeBounds[2], oldMarqueeBounds[3], UIBLACK);
  2124.             }
  2125.             FrameUIRect(marqueeBounds[0], marqueeBounds[1],
  2126.                     marqueeBounds[2], marqueeBounds[3], UIRED);
  2127.         }
  2128.         else
  2129.         {
  2130.             SetVar(corral, MARQUEE, marquee);
  2131.             DrawMe(corral);
  2132.         }
  2133.         }
  2134.     }
  2135.     if (nOverDrawPlanes)
  2136.     {
  2137.         FrameUIRect(marqueeBounds[0], marqueeBounds[1],
  2138.             marqueeBounds[2], marqueeBounds[3], UIBLACK);
  2139.         OverDraw(false);
  2140.     }
  2141.     SetVar(corral, MARQUEE, NULLOBJ);
  2142.  
  2143.     if (yesMarquee)
  2144.     {
  2145.         /*Go throught list of icons to determine which ones should be pressed*/
  2146.         runner = LISTOF(contents);
  2147.         while (runner)
  2148.         {
  2149.         ObjPtr icon;
  2150.         ObjPtr theLoc;
  2151.         real loc[2];
  2152.  
  2153.         icon = runner -> thing;
  2154.         theLoc = GetFixedArrayVar("PressCorralContents", icon, ICONLOC, 1, 2L);
  2155.         if (theLoc)
  2156.         {
  2157.         Array2CArray(loc, theLoc);
  2158.  
  2159.         if (loc[0] > marqueeBounds[0] - 16 &&
  2160.             loc[0] < marqueeBounds[1] + 16 &&
  2161.             loc[1] > marqueeBounds[2] - 8 &&
  2162.             loc[1] < marqueeBounds[3] + 32)
  2163.         {
  2164.             /*Select or deselect the icon*/
  2165.             if (IsIconSelected(icon))
  2166.                 {
  2167.             /*Already selected.  Only deselect if shift down*/
  2168.             if ((flags & F_SHIFTDOWN) || (TOOL(flags) == T_ROTATE))
  2169.             {
  2170.                 Select(icon, false);
  2171.             }
  2172.             }
  2173.             else
  2174.             {
  2175.             Select(icon, true);
  2176.             }
  2177.         }
  2178.         }
  2179.  
  2180.         runner = runner -> next;
  2181.         }
  2182.     }
  2183.  
  2184.     DrawMe(corral);
  2185.     }
  2186.  
  2187.     if (pressedIcon)
  2188.     {
  2189.     if ((flags & F_DOUBLECLICK) && IsIconSelected(pressedIcon))
  2190.     {
  2191.         /*Do it's doubleclick function*/
  2192.         DoUniqueTask(DoDoubleClickFunction);
  2193.     }
  2194.     else
  2195.     {
  2196.         /*Construct a list of icons and drag it*/
  2197.         ObjPtr iconList;
  2198.         iconList = NewList();
  2199.  
  2200.         runner = LISTOF(contents);
  2201.         while (runner)
  2202.         {
  2203.         if (IsIconSelected(runner -> thing) &&
  2204.             runner -> thing != pressedIcon)
  2205.         {
  2206.             PrefixList(iconList, runner -> thing);
  2207.         }
  2208.         runner = runner -> next;
  2209.         }
  2210.         PrefixList(iconList, pressedIcon);
  2211.         if (DragIcons(iconList, x, y))
  2212.         {
  2213.         dropObject = iconList;
  2214.         AddToReferenceList(iconList);
  2215.         }
  2216.     }
  2217.     }
  2218.  
  2219.     return ObjTrue;
  2220. }
  2221. #endif
  2222.  
  2223. #ifdef GRAPHICS
  2224. ObjPtr DrawField(object)
  2225. ObjPtr object;
  2226. /*Draws a field*/
  2227. {
  2228.     int left, right, bottom, top;
  2229.     ObjPtr backColor;            /*Color of the background*/
  2230.     FuncTyp drawContents;        /*Routine to draw the contents*/
  2231.     ObjPtr scrollBar;            /*Temporary place for the scroll bar*/
  2232.  
  2233.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  2234.     if (!IsDrawingRestricted(left, right, bottom, top))
  2235.     {
  2236.  
  2237.     /*Draw the background*/
  2238.     backColor = (ObjPtr) GetVar(object, BACKGROUND);
  2239.     if (backColor)
  2240.     {
  2241.     SetObjectColor(backColor);
  2242.     }
  2243.     else
  2244.     {
  2245.     SetUIColor(UIICONPIT);
  2246.     }
  2247.     DrawInsetRect(left, right, bottom, top);
  2248.     SetClipRect(left + EDGE, right - EDGE, bottom + EDGE, top - EDGE);
  2249.     
  2250.     drawContents = GetMethod(object, DRAWCONTENTS);
  2251.     if (drawContents)
  2252.     {
  2253.     int xOff, yOff;
  2254.     int fieldDepth;
  2255.     GETSCROLL(object, xOff, yOff);
  2256.     if (GetPredicate(object, BORDERTYPE))
  2257.     {
  2258.         fieldDepth = 1;
  2259.     }
  2260.     else
  2261.     {
  2262.         fieldDepth = EDGE;
  2263.     }
  2264.  
  2265.     if (GetPredicate(object, TOPDOWN))
  2266.     {
  2267.         SetOrigin(left + fieldDepth + xOff, top - fieldDepth + yOff);
  2268.     }
  2269.     else
  2270.     {
  2271.         SetOrigin(left + fieldDepth + xOff, bottom + fieldDepth + yOff);
  2272.     }
  2273.     (*drawContents)(object);
  2274.     RestoreOrigin();
  2275.     }
  2276.  
  2277.     RestoreClipRect();
  2278.     DrawSunkenEdge(left, right, bottom, top);
  2279.     }
  2280.  
  2281.     scrollBar = GetVar(object, HSCROLL);
  2282.     if (scrollBar)
  2283.     {
  2284.     DrawObject(scrollBar);
  2285.     }
  2286.  
  2287.     scrollBar = GetVar(object, VSCROLL);
  2288.     if (scrollBar)
  2289.     {
  2290.     DrawObject(scrollBar);
  2291.     }
  2292.     return ObjTrue;
  2293. }
  2294. #endif
  2295.  
  2296. #ifdef GRAPHICS
  2297. ObjPtr DrawControlField(object)
  2298. ObjPtr object;
  2299. /*Draws a control field*/
  2300. {
  2301.     int left, right, bottom, top;
  2302.     ObjPtr backColor;            /*Color of the background*/
  2303.     FuncTyp drawContents;        /*Routine to draw the contents*/
  2304.     ObjPtr scrollBar;            /*Temporary place for the scroll bar*/
  2305.     ObjPtr borderType;            /*Type of border*/
  2306.     int fieldDepth;
  2307.  
  2308.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  2309.  
  2310.     /*Draw the border*/
  2311.     borderType = GetVar(object, BORDERTYPE);
  2312.     if (borderType)
  2313.     {
  2314.     FrameUIRect(left, right, bottom, top, UIBLACK);
  2315.     }
  2316.  
  2317.     if (borderType)
  2318.     {
  2319.     fieldDepth = 1;
  2320.     }
  2321.     else
  2322.     {
  2323.     fieldDepth = EDGE;
  2324.     }
  2325.  
  2326.     SetClipRect(left + fieldDepth, right - fieldDepth,
  2327.         bottom + fieldDepth, top - fieldDepth);
  2328.  
  2329.     /*Get the color, if any, and draw it*/
  2330.     backColor = (ObjPtr) GetVar(object, BACKGROUND);
  2331.     if (backColor)
  2332.     {
  2333.     SetObjectColor(backColor);
  2334.     }
  2335.     else
  2336.     {
  2337.     SetUIColor(UICONTROLTRACK);
  2338.     }
  2339.     FillRect(left + fieldDepth, right - fieldDepth,
  2340.         bottom + fieldDepth, top - fieldDepth);
  2341.  
  2342.     /*Draw the contents of the panel*/
  2343.     drawContents = GetMethod(object, DRAWCONTENTS);
  2344.     if (drawContents)
  2345.     {
  2346.     int xOff, yOff;
  2347.  
  2348.     GETSCROLL(object, xOff, yOff);
  2349.  
  2350.     if (GetPredicate(object, TOPDOWN))
  2351.     {
  2352.         SetOrigin(left + fieldDepth + xOff, top - fieldDepth + yOff);
  2353.     }
  2354.     else
  2355.     {
  2356.         SetOrigin(left + fieldDepth + xOff, bottom + fieldDepth + yOff);
  2357.     }
  2358.  
  2359.     (*drawContents)(object);
  2360.     RestoreOrigin();
  2361.     }
  2362.  
  2363.     RestoreClipRect();
  2364.     if (!borderType)
  2365.     {
  2366.     DrawSunkenEdge(left, right, bottom, top);
  2367.     }
  2368.  
  2369.     scrollBar = GetVar(object, HSCROLL);
  2370.     if (scrollBar)
  2371.     {
  2372.     DrawObject(scrollBar);
  2373.     }
  2374.  
  2375.     scrollBar = GetVar(object, VSCROLL);
  2376.     if (scrollBar)
  2377.     {
  2378.     DrawObject(scrollBar);
  2379.     }
  2380.     return ObjTrue;
  2381. }
  2382. #endif
  2383.  
  2384. #ifdef GRAPHICS 
  2385. static ObjPtr DrawControlFieldContents(object)
  2386. ObjPtr object;
  2387. /*Draws a control field's contents*/
  2388. {
  2389.     ObjPtr contents;
  2390.     contents = GetVar(object, CONTENTS);
  2391.     if (contents)
  2392.     {
  2393.     DrawList(contents);
  2394.     }
  2395.     return ObjTrue;
  2396. }
  2397. #endif
  2398.  
  2399. #ifdef GRAPHICS
  2400. static ObjPtr DrawCorralContents(object)
  2401. ObjPtr object;
  2402. /*Draws the contents of an icon corral*/
  2403. {
  2404.     ObjPtr marquee;
  2405.     ObjPtr var;
  2406.     int viewBy;
  2407.  
  2408.     var = GetVar(object, VIEWBYWHAT);
  2409.     if (var)
  2410.     {
  2411.     viewBy = GetInt(var);
  2412.     }
  2413.     else
  2414.     {
  2415.     viewBy = VB_ICON;
  2416.     }
  2417.  
  2418.     if (viewBy == VB_ICON)
  2419.     {
  2420.     /*View by icon.  Just let the icons draw themselves*/
  2421.     real marqueeBounds[4];
  2422.     ObjPtr contents;
  2423.     Bool topDown;
  2424.  
  2425.     marquee = GetVar(object, MARQUEE);
  2426.     if (marquee)
  2427.     {
  2428.         Array2CArray(marqueeBounds, marquee);
  2429.         FrameUIRect(marqueeBounds[0] + 1.0,
  2430.             marqueeBounds[1] + 1.0,
  2431.             marqueeBounds[2] - 1.0,
  2432.             marqueeBounds[3] - 1.0, UIBLACK);
  2433.         
  2434.         FrameUIRect(marqueeBounds[0],
  2435.             marqueeBounds[1],
  2436.             marqueeBounds[2],
  2437.             marqueeBounds[3], UIWHITE);
  2438.     }
  2439.  
  2440.     /*Now draw the contents*/
  2441.  
  2442.     topDown = GetPredicate(object, TOPDOWN);
  2443.  
  2444.     contents = GetVar(object, CONTENTS);
  2445.     if (contents)
  2446.     {
  2447.         ThingListPtr runner;
  2448.         ObjPtr iconLoc;
  2449.         Bool anyNull;
  2450.         Bool anyNotNull;
  2451.         real loc[2];
  2452.         int minX, maxX, minY, maxY;
  2453.         int x, y;
  2454.         int xLeft, xRight;
  2455.         int k;
  2456.  
  2457.         /*See if any of the icons has a NULL ICONLOC*/
  2458.         runner = LISTOF(contents);
  2459.         anyNull = false;
  2460.         anyNotNull = false;
  2461.         while (runner)
  2462.         {
  2463.         iconLoc = GetVar(runner -> thing, ICONLOC);
  2464.         if (iconLoc)
  2465.         {
  2466.             Array2CArray(loc, iconLoc);
  2467.             if (anyNotNull)
  2468.             {
  2469.             /*Just another non-null location*/
  2470.             minX = MIN(minX, loc[0]);
  2471.             maxX = MAX(maxX, loc[0]);
  2472.             minY = MIN(minY, loc[1]);
  2473.             maxY = MAX(maxY, loc[1]);
  2474.             }
  2475.             else
  2476.             {
  2477.             /*First non-null location*/
  2478.             minX = maxX = loc[0];
  2479.             minY = maxY = loc[1];
  2480.                 anyNotNull = true;
  2481.             }
  2482.         }
  2483.         else
  2484.         {
  2485.             anyNull = true;
  2486.         }
  2487.         runner = runner -> next;
  2488.         }
  2489.         if (anyNull)
  2490.         {
  2491.         /*There must be at least some icons whose location is not
  2492.           set*/
  2493.         int left, right, bottom, top;
  2494.         Bool stagger;
  2495.  
  2496.         stagger = GetPrefTruth(PREF_STAGGERICONS);
  2497.  
  2498.         Get2DIntBounds(object, &left, &right, &bottom, &top);
  2499.         
  2500.         if (GetPredicate(object, SINGLECORRAL))
  2501.         {
  2502.             x = (right - left) / 2;
  2503.             y = topDown ?
  2504.             (bottom - top) / 2 + 25 :
  2505.             (top - bottom) / 2 + 25;
  2506.         }
  2507.         else
  2508.         {
  2509.             /*Find starting x and y below existing*/
  2510.  
  2511.             xLeft = ICONLEFTBORDER;
  2512.             xRight = right - left - ICONLEFTBORDER;
  2513.             if (xRight < xLeft) xRight = xLeft;
  2514.  
  2515.             if (!anyNotNull)
  2516.             {
  2517.             /*They're all null, pick a reasonable start*/
  2518.             
  2519.             if (topDown)
  2520.             {
  2521.                 y = -ICONTOPBORDER;
  2522.             }
  2523.             else
  2524.             {
  2525.                 y = ICONBOTBORDER;
  2526.             }
  2527.             }
  2528.             else
  2529.             {
  2530.             if (topDown)
  2531.             {
  2532.                 k = (-minY - ICONTOPBORDER + ICONYSPACE / 2) / ICONYSPACE;
  2533.                 ++k;
  2534.                 y = -ICONTOPBORDER - k * ICONYSPACE;
  2535.             }
  2536.             else
  2537.             {
  2538.                 k = (maxY - ICONBOTBORDER + ICONYSPACE / 2) / ICONYSPACE;
  2539.                 ++k;
  2540.                 y = k * ICONYSPACE + ICONBOTBORDER;
  2541.             }
  2542.             }
  2543.  
  2544.             x = xLeft;
  2545.         }
  2546.  
  2547.         /*Now go through list and find locations for the icons*/
  2548.         runner = LISTOF(contents);
  2549.         
  2550.         k = 0;
  2551.         while (runner)
  2552.         {
  2553.             if (GetVar(runner -> thing, ICONLOC) == NULLOBJ)
  2554.             {
  2555.             loc[0] = x;
  2556.             loc[1] = ((k & 1) && stagger) ? (y + (topDown ? -ICONYSPACE / 2 : ICONYSPACE / 2)) : y;
  2557. ;
  2558.             iconLoc = NewRealArray(1, 2L);
  2559.             CArray2Array(iconLoc, loc);
  2560.             SetVar(runner -> thing, ICONLOC, iconLoc);
  2561.  
  2562.             x += ICONXSPACE;
  2563.             ++k;
  2564.             if (x > xRight)
  2565.             {
  2566.                 x = xLeft;
  2567.                 y = topDown ? y - ICONYSPACE : y + ICONYSPACE;
  2568.                 k = 0;
  2569.             }
  2570.             }
  2571.             runner = runner -> next;
  2572.         }
  2573.         RecalcScroll(object);
  2574.         }
  2575.  
  2576.         DrawList(contents);
  2577.     }
  2578.     }
  2579.     return ObjTrue;
  2580. }
  2581. #endif
  2582.  
  2583. #ifdef GRAPHICS
  2584. static ObjPtr DrawSwitch(object)
  2585. ObjPtr object;
  2586. /*Draws a switch*/
  2587. {
  2588.     int left, right, bottom, top;
  2589.     ObjPtr var;
  2590.     int nCells;
  2591.     int outCell;
  2592.     int value;
  2593.     int k, x, y, cl, cr, c, y2;
  2594.     
  2595.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  2596.  
  2597.     /*Draw the background*/
  2598.     FillUIRect(left, right, bottom, top, UIBACKGROUND);
  2599.  
  2600.     /*Get the parameters*/
  2601.     var = GetVar(object, NCELLS);
  2602.     if (!var || !IsInt(var))
  2603.     {
  2604.     return;
  2605.     }
  2606.     nCells = GetInt(var);
  2607.  
  2608.     var = GetVar(object, OUTCELL);
  2609.     if (!var || !IsInt(var))
  2610.     {
  2611.     return;
  2612.     }
  2613.     outCell = GetInt(var);
  2614.  
  2615.     var = GetVar(object, VALUE);
  2616.     if (!var || !IsInt(var))
  2617.     {
  2618.     return;
  2619.     }
  2620.     value = GetInt(var);
  2621.  
  2622.     /*Set up temporary vars to make drawing easier*/
  2623.     c = (left + right) / 2 - SWITCHSLOPLEFT;
  2624.     if (c < left + SWITCHRADIUS) c = left + SWITCHRADIUS;
  2625.     cl = c - SWITCHRADIUS;
  2626.     cr = c + SWITCHRADIUS;
  2627.  
  2628.     /*Draw the background*/
  2629.     SetUIColor(UIBLACK);
  2630.     for (k = 0; k < nCells; ++k)
  2631.     {
  2632.     y = top - (top - bottom) * k / nCells - (top - bottom) / nCells / 2;
  2633.  
  2634.     DrawUILine(left, y, cl, y, UIBLACK);
  2635.     if (k < outCell)
  2636.     {
  2637.         /*Draw a curve downward*/
  2638.         DrawArc(cl, y - SWITCHRADIUS, SWITCHRADIUS, 0, 90);
  2639.     }
  2640.     else if (k > outCell)
  2641.     {
  2642.         /*Draw a curve upward*/
  2643.         DrawArc(cl, y + SWITCHRADIUS, SWITCHRADIUS, -90, 0);
  2644.     }
  2645.     else
  2646.     {
  2647.         /*Draw a junction*/
  2648.         if (k > 0)
  2649.         {
  2650.         /*Something coming in from above*/
  2651.         DrawArc(cr, y + SWITCHRADIUS, SWITCHRADIUS, 180, 270);
  2652.         }
  2653.         DrawUILine(cl, y, right, y, UIBLACK);
  2654.         if (k < nCells - 1)
  2655.         {
  2656.         /*Something coming in from below*/
  2657.         DrawArc(cr, y - SWITCHRADIUS, SWITCHRADIUS, 90, 180);
  2658.         }
  2659.     }
  2660.     }
  2661.  
  2662.     /*Draw the vertical lines*/
  2663.     if (outCell > 0)
  2664.     {
  2665.     /*There's a top part*/
  2666.     y = top - (top - bottom) / nCells / 2;
  2667.     y2 = top - (top - bottom) * outCell / nCells - (top - bottom) / nCells / 2;
  2668.     DrawUILine(c, y - SWITCHRADIUS, c, y2 + SWITCHRADIUS, UIBLACK);
  2669.     }
  2670.  
  2671.     if (outCell < nCells - 1)
  2672.     {
  2673.     /*There's a bottom part*/
  2674.     y = top - (top - bottom) * outCell / nCells - (top - bottom) / nCells / 2;
  2675.     y2 = top - (top - bottom) * (nCells - 1) / nCells - (top - bottom) / nCells / 2;
  2676.     DrawUILine(c, y - SWITCHRADIUS, c, y2 + SWITCHRADIUS, UIBLACK);
  2677.     }
  2678.  
  2679.     /*Draw the highlighted path*/
  2680.     if (value >= 0)
  2681.     {
  2682.     SetLineWidth(3);
  2683.  
  2684.     if (value < outCell)
  2685.     {
  2686.         /*Over, down, over*/
  2687.         y = top - (top - bottom) * value / nCells - (top - bottom) / nCells / 2;
  2688.         y2 = top - (top - bottom) * outCell / nCells - (top - bottom) / nCells / 2;
  2689.         DrawUILine(left, y, cl, y, UIBLACK);
  2690.         DrawArc(cl, y - SWITCHRADIUS, SWITCHRADIUS, 0, 90);
  2691.         DrawUILine(c, y - SWITCHRADIUS, c, y2 + SWITCHRADIUS, UIBLACK);
  2692.         DrawArc(cr, y2 + SWITCHRADIUS, SWITCHRADIUS, 180, 270);
  2693.         DrawUILine(cr, y2, right - 2, y2, UIBLACK);
  2694.     }
  2695.     else if (value > outCell)
  2696.     {
  2697.         /*Over, up, over*/
  2698.         y = top - (top - bottom) * value / nCells - (top - bottom) / nCells / 2;
  2699.         y2 = top - (top - bottom) * outCell / nCells - (top - bottom) / nCells / 2;
  2700.         DrawUILine(left, y, cl, y, UIBLACK);
  2701.         DrawArc(cl, y + SWITCHRADIUS, SWITCHRADIUS, -90, 0);
  2702.         DrawUILine(c, y + SWITCHRADIUS, c, y2 - SWITCHRADIUS, UIBLACK);
  2703.         DrawArc(cr, y2 - SWITCHRADIUS, SWITCHRADIUS, 90, 180);
  2704.         DrawUILine(cr, y2, right - 2, y2, UIBLACK);
  2705.     }
  2706.     else
  2707.     {
  2708.         /*Straight over*/
  2709.         y2 = top - (top - bottom) * value / nCells - (top - bottom) / nCells / 2;
  2710.         DrawUILine(left, y2, right - 2, y2, UIBLACK);
  2711.     }
  2712.     SetLineWidth(1);
  2713.  
  2714.     /*Draw half the arrow head*/
  2715.     FillTri(right - ARROWLENGTH, y2, right - ARROWLENGTH, y2 - ARROWHEIGHT, right, y2);
  2716.  
  2717.     /*Draw half the arrow head*/
  2718.     FillTri(right - ARROWLENGTH, y2, right - ARROWLENGTH, y2 + ARROWHEIGHT, right, y2);
  2719.     }
  2720.     else
  2721.     {
  2722.     /*Draw a single completion outcell*/
  2723.     y2 = top - (top - bottom) * outCell / nCells - (top - bottom) / nCells / 2;
  2724.     DrawUILine(cr, y2, right, y2, UIBLACK);
  2725.     }
  2726.     return ObjTrue;
  2727. }
  2728. #endif
  2729.  
  2730. #ifdef INTERACTIVE
  2731. static ObjPtr PressSwitch(object, mouseX, mouseY, flags)
  2732. ObjPtr object;
  2733. int mouseX, mouseY;
  2734. long flags;
  2735. /*Press in a switch*/
  2736. {
  2737.     int left, right, bottom, top;
  2738.     ObjPtr backColor;            /*Color of the background*/
  2739.     FuncTyp drawContents;        /*Routine to draw the contents*/
  2740.     ObjPtr var;
  2741.     int value;
  2742.     int trackCell;            /*The current cell to track*/
  2743.     int lastCell;            /*The last cell tracked in*/
  2744.     int nCells;                /*Number of cells in the switch*/
  2745.  
  2746.     Get2DIntBounds(object, &left, &right, &bottom, &top);
  2747.  
  2748.     if (mouseX < left || mouseX > right || mouseY < bottom || mouseY > top)
  2749.     {
  2750.     return ObjFalse;
  2751.     }
  2752.  
  2753.     if (TOOL(flags) == T_HELP)
  2754.     {
  2755.     ContextHelp(object);
  2756.     return ObjTrue;
  2757.     }
  2758.  
  2759.     SaveForUndo(object);
  2760.  
  2761.     /*Get the current value of the control*/
  2762.     var = GetIntVar("PressSwitch", object, VALUE);
  2763.     if (!var)
  2764.     { 
  2765.     return ObjFalse;
  2766.     }
  2767.     value = GetInt(var);
  2768.  
  2769.     /*Get ncells*/
  2770.     var = GetIntVar("PressSwitch", object, NCELLS);
  2771.     if (!var)
  2772.     { 
  2773.     return ObjFalse;
  2774.     }
  2775.     nCells = GetInt(var);
  2776.  
  2777.     /*Get lastCell*/
  2778.     trackCell = lastCell = nCells - 1 - (mouseY - bottom) * nCells / (top - bottom);
  2779.     if (lastCell >= nCells) lastCell = nCells - 1;
  2780.     if (lastCell < 0) lastCell = 0;
  2781.     SetVar(object, VALUE, NewInt(lastCell));
  2782.     DrawMe(object);
  2783.  
  2784.     InhibitLogging(true);
  2785.     while (Mouse(&mouseX, &mouseY))
  2786.     {
  2787.     if (mouseX < left || mouseX > right || mouseY < bottom || mouseY > top)
  2788.     {
  2789.         trackCell = value;
  2790.     }
  2791.     else
  2792.     {
  2793.         trackCell = nCells - 1 - (mouseY - bottom) * nCells / (top - bottom);
  2794.         if (trackCell >= nCells) trackCell = nCells - 1;
  2795.         if (trackCell < 0) trackCell = 0;
  2796.     }
  2797.     if (trackCell != lastCell)
  2798.     {
  2799.         lastCell = trackCell;
  2800.         SetVar(object, VALUE, NewInt(trackCell));
  2801.         DrawMe(object);
  2802.     }
  2803.     }
  2804.     InhibitLogging(false);
  2805.     if (logging)
  2806.     {
  2807.     LogControl(object);
  2808.     }
  2809.     if (logging || (trackCell != value))
  2810.     {
  2811.     ChangedValue(object);
  2812.     }
  2813.     return ObjTrue;
  2814. }
  2815. #endif
  2816.  
  2817. ObjPtr RecalcCorralScroll(corral)
  2818. ObjPtr corral;
  2819. /*Recalculates the scroll parameters in an icon corral*/
  2820. {
  2821.     real minx, maxx, miny, maxy;
  2822.     real iconLoc[2], bounds[4];
  2823.     Bool boundsSet;
  2824.     int left, right, bottom, top;
  2825.     ObjPtr var, vScroll, hScroll;
  2826.     ObjPtr contents;
  2827.     ThingListPtr list;
  2828.     int fieldDepth;
  2829.     
  2830.     if (GetPredicate(corral, BORDERTYPE))
  2831.     {
  2832.     fieldDepth = 1;
  2833.     }
  2834.     else
  2835.     {
  2836.     fieldDepth = EDGE;
  2837.     }
  2838.  
  2839.     /*Get bounds*/
  2840.     Get2DIntBounds(corral, &left, &right, &bottom, &top);
  2841.     bounds[0] = left;
  2842.     bounds[1] = right;
  2843.     bounds[2] = bottom;
  2844.     bounds[3] = top;
  2845.  
  2846.     /*Look through icons*/
  2847.     contents = GetListVar("RecalcCorralScroll", corral, CONTENTS);
  2848.     if (!contents) return ObjFalse;
  2849.     list = LISTOF(contents);
  2850.  
  2851.     boundsSet = false;
  2852.     /*Go through the rest of the icons*/
  2853.     while (list)
  2854.     {
  2855.     var = GetVar(list -> thing, ICONLOC);
  2856.     if (var)
  2857.     {
  2858.             Array2CArray(iconLoc, var);
  2859.  
  2860.             if (boundsSet)
  2861.             {
  2862.  
  2863.                 if (iconLoc[0] - ICONLEFTBORDER < minx)
  2864.                 {
  2865.                     minx = iconLoc[0] - ICONLEFTBORDER;
  2866.                 }
  2867.                 if (iconLoc[0] + ICONRIGHTBORDER > maxx)
  2868.                 {
  2869.                     maxx = iconLoc[0] + ICONRIGHTBORDER;
  2870.                 }
  2871.                 if (iconLoc[1] - ICONBOTBORDER < miny)
  2872.                 {
  2873.                     miny = iconLoc[1] - ICONBOTBORDER;
  2874.                 }
  2875.                 if (iconLoc[1] + ICONTOPBORDER > maxy)
  2876.                 {
  2877.                     maxy = iconLoc[1] + ICONTOPBORDER;
  2878.                 }
  2879.             }
  2880.             else
  2881.             {
  2882.                 minx = iconLoc[0] - ICONLEFTBORDER;
  2883.                 maxx = iconLoc[0] + ICONRIGHTBORDER;
  2884.                 miny = iconLoc[1] - ICONBOTBORDER;
  2885.                 maxy = iconLoc[1] + ICONTOPBORDER;
  2886.                 boundsSet = true;
  2887.             }
  2888.     }
  2889.     list = list -> next;
  2890.     }
  2891.  
  2892.     if (boundsSet)
  2893.     {
  2894.     /*Adjust hscroll*/
  2895.     hScroll = GetVar(corral, HSCROLL);
  2896.     if (hScroll)
  2897.     {
  2898.     real sliderBottom, sliderTop;
  2899.     real portionShown;
  2900.     real val;
  2901.  
  2902.     var = GetValue(hScroll);
  2903.     val = GetReal(var);
  2904.  
  2905.     sliderTop = maxx - (bounds[1] - bounds[0]) - fieldDepth * 2;
  2906.     if (sliderTop < val) sliderTop = val;
  2907.  
  2908.     sliderBottom = minx;
  2909.     if (sliderBottom > val) sliderBottom = val;
  2910.  
  2911.     SetSliderRange(hScroll, sliderTop, sliderBottom, 20.0);
  2912.  
  2913.     portionShown = bounds[1] - bounds[0] - fieldDepth * 2;
  2914. /*
  2915.     if (portionShown > sliderTop - sliderBottom) portionShown = sliderTop - sliderBottom;
  2916. */
  2917.     SetPortionShown(hScroll, portionShown);
  2918.     }
  2919.  
  2920.     /*Adjust vscroll*/
  2921.     vScroll = GetVar(corral, VSCROLL);
  2922.     if (vScroll)
  2923.     {
  2924.     real sliderTop, sliderBottom;
  2925.     real val;
  2926.     real portionShown;
  2927.  
  2928.     var = GetValue(vScroll);
  2929.     val = GetReal(var);
  2930.  
  2931.     if (GetPredicate(corral, TOPDOWN))
  2932.     {
  2933.         sliderTop = maxy;
  2934.         sliderBottom = miny + (bounds[3] - bounds[2]) - fieldDepth * 2;
  2935.     }
  2936.     else
  2937.     {
  2938.         sliderTop = maxy - (bounds[3] - bounds[2]) - fieldDepth * 2;
  2939.         sliderBottom = miny;
  2940.     }
  2941.     if (sliderTop < val) sliderTop = val;
  2942.     if (sliderBottom > val) sliderBottom = val;
  2943.     SetSliderRange(vScroll, sliderTop, sliderBottom, 20.0);
  2944.  
  2945.     portionShown = bounds[3] - bounds[2] - fieldDepth * 2;
  2946. /*
  2947.     if (portionShown > sliderTop - sliderBottom) portionShown = sliderTop - sliderBottom;
  2948. */
  2949.     SetPortionShown(vScroll, portionShown);
  2950.     }
  2951.  
  2952.     /*Set the virtual bounds*/
  2953.     if (hScroll) bounds[1] -= BARWIDTH + CORRALBARBORDER;
  2954.     if (vScroll) bounds[3] -= BARWIDTH + CORRALBARBORDER;
  2955.     if (minx < bounds[0]) bounds[0] = minx;
  2956.     if (maxx > bounds[1]) bounds[1] = maxx;
  2957.     if (miny < bounds[2]) bounds[2] = miny;
  2958.     if (maxy > bounds[3]) bounds[3] = maxy;
  2959.     var = NewRealArray(1, 4L);
  2960.     CArray2Array(var, bounds);
  2961.     SetVar(corral, VIRTUALBOUNDS, var);
  2962.     }
  2963.  
  2964.     return ObjTrue;
  2965. }
  2966.  
  2967. ObjPtr RecalcControlFieldScroll(field)
  2968. ObjPtr field;
  2969. /*Recalculates the scroll parameters in a control field*/
  2970. {
  2971.     int minx, maxx, miny, maxy;
  2972.     real bounds[4];
  2973.     int left, right, bottom, top;
  2974.     ObjPtr var, vScroll, hScroll;
  2975.     ObjPtr contents;
  2976.     ThingListPtr list;
  2977.     int fieldDepth;
  2978.     
  2979.     if (GetPredicate(field, BORDERTYPE))
  2980.     {
  2981.     fieldDepth = 1;
  2982.     }
  2983.     else
  2984.     {
  2985.     fieldDepth = EDGE;
  2986.     }
  2987.     
  2988.     /*Get bounds*/
  2989.     Get2DIntBounds(field, &left, &right, &bottom, &top);
  2990.     bounds[0] = left;
  2991.     bounds[1] = right;
  2992.     bounds[2] = bottom;
  2993.     bounds[3] = top;
  2994.  
  2995.     /*Look through objects*/
  2996.     contents = GetListVar("RecalcControlFieldScroll", field, CONTENTS);
  2997.     if (!contents) return ObjFalse;
  2998.     list = LISTOF(contents);
  2999.  
  3000.     /*Get first object*/
  3001.     if (list)
  3002.     {
  3003.     Get2DIntBounds(list -> thing, &left, &right, &bottom, &top);
  3004.     list = list -> next;
  3005.     }
  3006.     else
  3007.     {
  3008.     left = right = 0;
  3009.     bottom = top = 0;
  3010.     }
  3011.     minx = left - MINORBORDER;
  3012.     maxx = right + MINORBORDER;
  3013.     miny = bottom - MINORBORDER;
  3014.     maxy = top + MINORBORDER;
  3015.  
  3016.     /*Go through the rest of the objects*/
  3017.     while (list)
  3018.     {
  3019.     Get2DIntBounds(list -> thing, &left, &right, &bottom, &top);
  3020.  
  3021.     minx = MIN(minx, left - MINORBORDER);
  3022.     maxx = MAX(maxx, right + MINORBORDER);
  3023.     miny = MIN(miny, bottom - MINORBORDER);
  3024.     maxy = MAX(maxy, top + MINORBORDER);
  3025.     list = list -> next;
  3026.     }
  3027.  
  3028.     /*Adjust hscroll*/
  3029.     hScroll = GetVar(field, HSCROLL);
  3030.     if (hScroll)
  3031.     {
  3032.     real sliderBottom, sliderTop;
  3033.     real portionShown;
  3034.     real val;
  3035.  
  3036.     var = GetValue(hScroll);
  3037.     val = GetReal(var);
  3038.  
  3039.     sliderTop = maxx - (bounds[1] - bounds[0]) - fieldDepth * 2;
  3040.     if (sliderTop < val) sliderTop = val;
  3041.  
  3042.     sliderBottom = minx;
  3043.     if (sliderBottom > val) sliderBottom = val;
  3044.  
  3045.     SetSliderRange(hScroll, sliderTop, sliderBottom, 20.0);
  3046.  
  3047.     portionShown = bounds[1] - bounds[0] - fieldDepth * 2;
  3048. /*
  3049.     if (portionShown > sliderTop - sliderBottom) portionShown = sliderTop - sliderBottom;
  3050. */
  3051.     SetPortionShown(hScroll, portionShown);
  3052.     }
  3053.  
  3054.     /*Adjust vscroll*/
  3055.     vScroll = GetVar(field, VSCROLL);
  3056.     if (vScroll)
  3057.     {
  3058.     real sliderTop, sliderBottom;
  3059.     real val;
  3060.     real portionShown;
  3061.  
  3062.     var = GetValue(vScroll);
  3063.     val = GetReal(var);
  3064.  
  3065.     if (GetPredicate(field, TOPDOWN))
  3066.     {
  3067.         sliderTop = maxy;
  3068.         sliderBottom = miny + (bounds[3] - bounds[2]) - fieldDepth * 2;
  3069.     }
  3070.     else
  3071.     {
  3072.         sliderTop = maxy - (bounds[3] - bounds[2]) - fieldDepth * 2;
  3073.         sliderBottom = miny;
  3074.     }
  3075.     if (sliderTop < val) sliderTop = val;
  3076.     if (sliderBottom > val) sliderBottom = val;
  3077.     SetSliderRange(vScroll, sliderTop, sliderBottom, 20.0);
  3078.  
  3079.     portionShown = bounds[3] - bounds[2] - fieldDepth * 2;
  3080. /*
  3081.     if (portionShown > sliderTop - sliderBottom) portionShown = sliderTop - sliderBottom;
  3082. */
  3083.     SetPortionShown(vScroll, portionShown);
  3084.     }
  3085.  
  3086.     /*Set the virtual bounds*/
  3087.     if (hScroll) bounds[1] -= BARWIDTH + CORRALBARBORDER;
  3088.     if (vScroll) bounds[3] -= BARWIDTH + CORRALBARBORDER;
  3089.     if (minx < bounds[0]) bounds[0] = minx;
  3090.     if (maxx > bounds[1]) bounds[1] = maxx;
  3091.     if (miny < bounds[2]) bounds[2] = miny;
  3092.     if (maxy > bounds[3]) bounds[3] = maxy;
  3093.     var = NewRealArray(1, 4L);
  3094.     CArray2Array(var, bounds);
  3095.     SetVar(field, VIRTUALBOUNDS, var);
  3096.  
  3097.     return ObjTrue;
  3098. }
  3099.  
  3100. ObjPtr SetSwitchVal(object, value)
  3101. ObjPtr object;
  3102. ObjPtr value;
  3103. /*Sets the value of the object to value*/
  3104. {
  3105.     if (IsInt(value))
  3106.     {
  3107.     int newValue, oldValue;
  3108.     ObjPtr var;
  3109.     newValue = GetInt(value);
  3110.     var = GetIntVar("SetSwitchVal", object, VALUE);
  3111.     if (!var) return false;
  3112.     oldValue = GetInt(var);
  3113.     if (newValue != oldValue)
  3114.     {
  3115.         SetVar(object, VALUE, NewInt(newValue));
  3116.         ImInvalid(object);
  3117.         ChangedValue(object);
  3118.     }
  3119.     if (logging)
  3120.     {
  3121.         LogControl(object);
  3122.     }
  3123.     return ObjTrue;
  3124.     }
  3125.     else if (IsReal(value))
  3126.     {
  3127.     int newValue, oldValue;
  3128.     ObjPtr var;
  3129.     newValue = (int) GetReal(value);
  3130.     var = GetIntVar("SetSwitchVal", object, VALUE);
  3131.     if (!var) return false;
  3132.     oldValue = GetInt(var);
  3133.     if (newValue != oldValue)
  3134.     {
  3135.         SetVar(object, VALUE, NewInt(newValue));
  3136.         ImInvalid(object);
  3137.         ChangedValue(object);
  3138.     }
  3139.     if (logging)
  3140.     {
  3141.         LogControl(object);
  3142.     }
  3143.     return ObjTrue;
  3144.     }
  3145.     else
  3146.     {
  3147.     return ObjFalse;
  3148.     }
  3149. }
  3150.  
  3151. ObjPtr ReshapeCorral(object, ol, or, ob, ot, left, right, bottom, top)
  3152. ObjPtr object;
  3153. int ol, or, ob, ot;
  3154. int left, right, bottom, top;
  3155. /*Reshapes object, which used to exist within owner with edges ol, or, ob, ot
  3156.   to one which exists within owner with edges left, right, bottom, top.*/
  3157. {
  3158.     ObjPtr boundsArray;
  3159.     ObjPtr stickyInt;
  3160.     real bounds[4];
  3161.     real oldWidth, oldHeight;    /*Old width and height*/
  3162.     Bool sideLocked[4];        /*True iff side is locked*/
  3163.     Bool xStretch, yStretch;    /*Stretchiness in x and y*/
  3164.     int stickiness;        /*Side stickiness of the object*/
  3165.     real oldBounds[4];        /*Old bounds of the object*/
  3166.     ObjPtr contents;        /*Contents of the object, if any*/
  3167.     ObjPtr scrollBar;        /*Scroll bar to reshape*/
  3168.     real scrollBounds[4];        /*Bounds of scroll bar*/
  3169.     real wr, hr;            /*Width and height ratios*/
  3170.  
  3171.     wr = ((real) (right - left)) / ((real) (or - ol));
  3172.     hr = ((real) (top - bottom)) / ((real) (ot - ob));
  3173.  
  3174.     boundsArray = GetVar(object, BOUNDS);
  3175.     if (!boundsArray || !IsRealArray(boundsArray) || RANK(boundsArray) != 1 ||
  3176.         DIMS(boundsArray)[0] != 4)
  3177.     {
  3178.         return ObjFalse;
  3179.     }
  3180.     Array2CArray(bounds, boundsArray);
  3181.     Array2CArray(oldBounds, boundsArray);
  3182.     oldWidth = bounds[1] - bounds[0];
  3183.     oldHeight = bounds[3] - bounds[2];
  3184.  
  3185.     /*Get the object's stickiness*/
  3186.     stickyInt = GetVar(object, STICKINESS);
  3187.     if (stickyInt && IsInt(stickyInt))
  3188.     {
  3189.         stickiness = GetInt(stickyInt);
  3190.     }
  3191.     else
  3192.     {
  3193.         stickiness = 0;
  3194.     }
  3195.  
  3196.     if ((stickiness & STICKYLEFT) || (stickiness & FLOATINGLEFT))
  3197.     {
  3198.         if (stickiness & FLOATINGLEFT)
  3199.         {
  3200.         bounds[0] = (bounds[0] - ol) * wr + left;
  3201.         }
  3202.         else
  3203.         {
  3204.         bounds[0] += left - ol;
  3205.         }
  3206.         if (!((stickiness & STICKYRIGHT) || (stickiness & FLOATINGRIGHT)))
  3207.         {
  3208.         bounds[1] = bounds[0] + oldWidth;
  3209.         }
  3210.     }
  3211.     if ((stickiness & STICKYRIGHT) || (stickiness & FLOATINGRIGHT))
  3212.     {
  3213.         if (stickiness & FLOATINGRIGHT)
  3214.         {
  3215.         bounds[1] = (bounds[1] - ol) * wr + left;
  3216.         }
  3217.         else
  3218.         {
  3219.         bounds[1] += right - or;
  3220.         }
  3221.         if (!((stickiness & STICKYLEFT) || (stickiness & FLOATINGLEFT)))
  3222.         {
  3223.         bounds[0] = bounds[1] - oldWidth;
  3224.         }
  3225.     }
  3226.  
  3227.     if ((stickiness & STICKYBOTTOM) || (stickiness & FLOATINGBOTTOM))
  3228.     {
  3229.         if (stickiness & FLOATINGBOTTOM)
  3230.         {
  3231.         bounds[2] = (bounds[2] - ob) * hr + bottom;
  3232.         }
  3233.         else
  3234.         {
  3235.         bounds[2] += bottom - ob;
  3236.         }
  3237.         if (!((stickiness & STICKYTOP) || (stickiness & FLOATINGTOP)))
  3238.         {
  3239.         bounds[3] = bounds[2] + oldHeight;
  3240.         }
  3241.     }
  3242.     if ((stickiness & STICKYTOP) || (stickiness & FLOATINGTOP))
  3243.     {
  3244.         if (stickiness & FLOATINGTOP)
  3245.         {
  3246.         bounds[3] = (bounds[3] - ob) * hr + bottom;
  3247.         }
  3248.         else
  3249.         {
  3250.         bounds[3] += top - ot;
  3251.         }
  3252.         if (!((stickiness & STICKYBOTTOM) || (stickiness & FLOATINGBOTTOM)))
  3253.         {
  3254.         bounds[2] = bounds[3] - oldHeight;
  3255.         }
  3256.     }
  3257.  
  3258.     /*We've got a new bounds, put it back*/
  3259.     boundsArray = NewRealArray(1, 4L);
  3260.     CArray2Array(boundsArray, bounds);
  3261.     SetVar(object, BOUNDS, boundsArray);
  3262.  
  3263.     /*Reshape the scroll bars*/
  3264.     scrollBar = GetVar(object, VSCROLL);
  3265.     if (scrollBar)
  3266.     {
  3267.         /*Get the bounds*/
  3268.         real width;
  3269.         boundsArray = GetFixedArrayVar("ReshapeCorral", scrollBar, BOUNDS, 1, 4L);
  3270.         if (!boundsArray) return ObjFalse;
  3271.  
  3272.         Array2CArray(scrollBounds, boundsArray);
  3273.         width = scrollBounds[1] - scrollBounds[0];
  3274.         if (scrollBounds[0] > oldBounds[1])
  3275.         {
  3276.         /*It was on the right*/
  3277.         scrollBounds[0] = bounds[1] + (scrollBounds[0] - oldBounds[1]);
  3278.         scrollBounds[1] = scrollBounds[0] + width;
  3279.         scrollBounds[2] = bounds[2];
  3280.         scrollBounds[3] = bounds[3];
  3281.         
  3282.         boundsArray = NewRealArray(1, 4L);
  3283.         CArray2Array(boundsArray, scrollBounds);
  3284.         SetVar(scrollBar, BOUNDS, boundsArray);
  3285.         }
  3286.         else
  3287.         {
  3288.         /*It was on the left*/
  3289.         scrollBounds[1] = bounds[0] + (scrollBounds[1] - oldBounds[0]);
  3290.         scrollBounds[0] = scrollBounds[1] - width;
  3291.         scrollBounds[2] = bounds[2];
  3292.         scrollBounds[3] = bounds[3];
  3293.         
  3294.         boundsArray = NewRealArray(1, 4L);
  3295.         CArray2Array(boundsArray, scrollBounds);
  3296.         SetVar(scrollBar, BOUNDS, boundsArray);
  3297.         }
  3298.     }
  3299.     scrollBar = GetVar(object, HSCROLL);
  3300.     if (scrollBar)
  3301.     {
  3302.         /*Get the bounds*/
  3303.         real height;
  3304.         boundsArray = GetFixedArrayVar("ReshapeCorral", scrollBar, BOUNDS, 1, 4L);
  3305.         if (!boundsArray) return ObjFalse;
  3306.  
  3307.         Array2CArray(scrollBounds, boundsArray);
  3308.         height = scrollBounds[3] - scrollBounds[2];
  3309.         if (scrollBounds[2] > oldBounds[3])
  3310.         {
  3311.         /*It was on the top*/
  3312.         scrollBounds[0] = bounds[0];
  3313.         scrollBounds[1] = bounds[1];
  3314.         scrollBounds[2] = bounds[3] + (scrollBounds[2] - oldBounds[3]);
  3315.         scrollBounds[3] = scrollBounds[2] + height;
  3316.         
  3317.         boundsArray = NewRealArray(1, 4L);
  3318.         CArray2Array(boundsArray, scrollBounds);
  3319.         SetVar(scrollBar, BOUNDS, boundsArray);
  3320.         }
  3321.         else
  3322.         {
  3323.         /*It was on the bottom*/
  3324.         scrollBounds[0] = bounds[0];
  3325.         scrollBounds[1] = bounds[1];
  3326.         scrollBounds[3] = bounds[2] + (scrollBounds[3] - oldBounds[2]);
  3327.         scrollBounds[2] = scrollBounds[3] - height;
  3328.         
  3329.         boundsArray = NewRealArray(1, 4L);
  3330.         CArray2Array(boundsArray, scrollBounds);
  3331.         SetVar(scrollBar, BOUNDS, boundsArray);
  3332.         }
  3333.     }
  3334.     RecalcScroll(object);
  3335.     return ObjTrue;
  3336. }
  3337.  
  3338. ObjPtr NewPanel(superClass, left, right, bottom, top)
  3339. ObjPtr superClass;
  3340. int left, right, bottom, top;
  3341. /*Makes a new panel with bounds left, right, bottom, top*/
  3342. {
  3343.     ObjPtr retVal;
  3344.     ObjPtr contents;
  3345.  
  3346.     retVal = NewObject(superClass ? superClass : panelClass, 0);
  3347.     Set2DIntBounds(retVal, left, right, bottom, top);
  3348.     SetVar(retVal, CONTENTS, contents = NewList());
  3349.     SetVar(contents, PARENT, retVal);
  3350.     return retVal;
  3351. }
  3352.  
  3353. ObjPtr ChangeFieldScroll(scrollBar)
  3354. ObjPtr scrollBar;
  3355. /*Changes the field scrolling*/
  3356. {
  3357.     ObjPtr repObj;
  3358.  
  3359.     repObj = GetObjectVar("ChangeFieldScroll", scrollBar, REPOBJ);
  3360.     if (!repObj)
  3361.     {
  3362.     return ObjFalse;
  3363.     }
  3364.     /*For now, just need to invalidate the field*/
  3365.     ImInvalid(repObj);
  3366.     return ObjTrue;
  3367. }
  3368.  
  3369. ObjPtr NewControlField(left, right, bottom, top, name, scrollBars)
  3370. int left, right, bottom, top;
  3371. char *name;
  3372. int scrollBars;
  3373. /*Makes a new control field*/
  3374. {
  3375.     ObjPtr retVal;
  3376.     ObjPtr contents;
  3377.     ObjPtr hScrollBar = NULLOBJ, vScrollBar = NULLOBJ;
  3378.  
  3379.     retVal = NewObject(controlFieldClass, 0);
  3380.     SetVar(retVal, CONTENTS, contents = NewList());
  3381.     SetVar(contents, PARENT, retVal);
  3382.     SetVar(retVal, NAME, NewString(name));
  3383.  
  3384.     if (scrollBars & BARRIGHT)
  3385.     {
  3386.     right -= BARWIDTH + CORRALBARBORDER;
  3387.     }
  3388.     if (scrollBars & BARLEFT)
  3389.     {
  3390.     left += BARWIDTH + CORRALBARBORDER;
  3391.     }
  3392.  
  3393.     if (scrollBars & BARBOTTOM)
  3394.     {
  3395.     bottom += BARWIDTH + CORRALBARBORDER;
  3396.     }
  3397.  
  3398.     if (scrollBars & BARRIGHT)
  3399.     {
  3400.     vScrollBar = NewScrollbar(right + CORRALBARBORDER,
  3401.             right + CORRALBARBORDER + BARWIDTH,
  3402.             bottom,
  3403.             top, "FVScroll");
  3404.     SetVar(retVal, VSCROLL, vScrollBar);
  3405.     SetVar(vScrollBar, PARENT, retVal);
  3406.     SetVar(vScrollBar, REPOBJ, retVal);
  3407.     SetMethod(vScrollBar, CHANGEDVALUE, ChangeFieldScroll);
  3408.     }
  3409.     else if (scrollBars & BARLEFT)
  3410.     {
  3411.     vScrollBar = NewScrollbar(left - CORRALBARBORDER - BARWIDTH,
  3412.             left - CORRALBARBORDER,
  3413.             bottom,
  3414.             top, "FVScroll");
  3415.     SetVar(retVal, VSCROLL, vScrollBar);
  3416.     SetVar(vScrollBar, PARENT, retVal);
  3417.     SetVar(vScrollBar, REPOBJ, retVal);
  3418.     SetMethod(vScrollBar, CHANGEDVALUE, ChangeFieldScroll);
  3419.     }
  3420.  
  3421.     if (scrollBars & BARBOTTOM)
  3422.     {
  3423.     hScrollBar = NewScrollbar(left,
  3424.             right,
  3425.             bottom - CORRALBARBORDER - BARWIDTH,
  3426.             bottom - CORRALBARBORDER,
  3427.             "FHScroll");
  3428.     SetVar(retVal, HSCROLL, hScrollBar);
  3429.     SetVar(hScrollBar, PARENT, retVal);
  3430.     SetVar(hScrollBar, REPOBJ, retVal);
  3431.     SetMethod(hScrollBar, CHANGEDVALUE, ChangeFieldScroll);
  3432.     SetVar(hScrollBar, REPOBJ, retVal);
  3433.     SetMethod(hScrollBar, CHANGEDVALUE, ChangeFieldScroll);
  3434.     }
  3435.  
  3436.     if (scrollBars & OBJECTSFROMTOP)
  3437.     {
  3438.     SetVar(retVal, TOPDOWN, ObjTrue);
  3439.     if (vScrollBar)
  3440.     {
  3441.         SetSliderRange(vScrollBar, 0.0, -10.0, 0.0);
  3442.     }
  3443.     }
  3444.  
  3445.     Set2DIntBounds(retVal, left, right, bottom, top);
  3446.     return retVal;
  3447. }
  3448.  
  3449. ObjPtr NewIconCorral(superClass, left, right, bottom, top, scrollBars)
  3450. ObjPtr superClass;
  3451. int left, right, bottom, top;
  3452. int scrollBars;
  3453. /*Makes a new panel with bounds left, right, bottom, top
  3454.   if superClass non-nil, uses that as the superclass of the object
  3455.   scrollBars is a bunch of flags for scroll bars AND OTHER STUFF*/
  3456. {
  3457.     ObjPtr retVal;
  3458.     ObjPtr hScrollBar = NULLOBJ, vScrollBar = NULLOBJ;
  3459.     ObjPtr contents;
  3460.  
  3461.     retVal = NewObject(superClass ? superClass : corralClass, 0);
  3462.     SetVar(retVal, CONTENTS, contents = NewList());
  3463.     SetVar(contents, PARENT, retVal);
  3464.  
  3465.     if (scrollBars & BARRIGHT)
  3466.     {
  3467.     right -= BARWIDTH + CORRALBARBORDER;
  3468.     }
  3469.     if (scrollBars & BARLEFT)
  3470.     {
  3471.     left += BARWIDTH + CORRALBARBORDER;
  3472.     }
  3473.  
  3474.     if (scrollBars & BARBOTTOM)
  3475.     {
  3476.     bottom += BARWIDTH + CORRALBARBORDER;
  3477.     }
  3478.     
  3479.     if (scrollBars & BARRIGHT)
  3480.     {
  3481.     vScrollBar = NewScrollbar(right + CORRALBARBORDER,
  3482.             right + CORRALBARBORDER + BARWIDTH,
  3483.             bottom,
  3484.             top, "VScroll");
  3485.     SetVar(retVal, VSCROLL, vScrollBar);
  3486.     SetVar(vScrollBar, PARENT, retVal);
  3487.     SetVar(vScrollBar, REPOBJ, retVal);
  3488.     SetMethod(vScrollBar, CHANGEDVALUE, ChangeFieldScroll);
  3489.     }
  3490.     else if (scrollBars & BARLEFT)
  3491.     {
  3492.     vScrollBar = NewScrollbar(left - CORRALBARBORDER - BARWIDTH,
  3493.             left - CORRALBARBORDER,
  3494.             bottom,
  3495.             top, "VScroll");
  3496.     SetVar(retVal, VSCROLL, vScrollBar);
  3497.     SetVar(vScrollBar, PARENT, retVal);
  3498.     SetVar(vScrollBar, REPOBJ, retVal);
  3499.     SetMethod(vScrollBar, CHANGEDVALUE, ChangeFieldScroll);
  3500.     }
  3501.  
  3502.     if (scrollBars & BARBOTTOM)
  3503.     {
  3504.     hScrollBar = NewScrollbar(left,
  3505.             right,
  3506.             bottom - CORRALBARBORDER - BARWIDTH,
  3507.             bottom - CORRALBARBORDER,
  3508.             "HScroll");
  3509.     SetVar(retVal, HSCROLL, hScrollBar);
  3510.     SetVar(hScrollBar, PARENT, retVal);
  3511.     SetVar(hScrollBar, REPOBJ, retVal);
  3512.     SetMethod(hScrollBar, CHANGEDVALUE, ChangeFieldScroll);
  3513.     }
  3514.  
  3515.     if (scrollBars & OBJECTSFROMTOP)
  3516.     {
  3517.     SetVar(retVal, TOPDOWN, ObjTrue);
  3518.     if (vScrollBar)
  3519.     {
  3520.         SetSliderRange(vScrollBar, 0.0, -10.0, 0.0);
  3521.     }
  3522.     }
  3523.  
  3524.     Set2DIntBounds(retVal, left, right, bottom, top);
  3525.  
  3526.     return retVal;
  3527. }
  3528.  
  3529. ObjPtr NewSwitch(left, right, bottom, top, nCells, outCell, initValue, name)
  3530. int left, right, bottom, top;
  3531. int nCells, outCell, initValue;
  3532. char *name;
  3533. /*Makes a new switch with bounds left, right, bottom, top
  3534.   nCells is the number of cells, outCell is which cell is the output,
  3535.   initValue is the initial switch*/
  3536. {
  3537.     ObjPtr retVal;
  3538.  
  3539.     retVal = NewObject(switchClass, 0);
  3540.     Set2DIntBounds(retVal, left, right, bottom, top);
  3541.     SetVar(retVal, NCELLS, NewInt(nCells));
  3542.     SetVar(retVal, OUTCELL, NewInt(outCell));
  3543.     SetVar(retVal, VALUE, NewInt(initValue));
  3544.     SetVar(retVal, NAME, NewString(name));
  3545.     return retVal;
  3546. }
  3547.  
  3548. #ifdef PROTO
  3549. real ChooseGoodStep(real min, real max)
  3550. #else
  3551. real ChooseGoodStep(min, max)
  3552. real min;
  3553. real max;
  3554. #endif
  3555. /*Choose a good step to get between min and max*/
  3556. {
  3557.     real diff;
  3558.     real exp;
  3559.  
  3560.     diff = max - min;
  3561.     exp = rfloor(rlog10(diff));
  3562.     return rpow(10.0, exp);
  3563. }
  3564.  
  3565. #ifdef PROTO
  3566. void ChooseGoodRange(real *min, real *max)
  3567. #else
  3568. void ChooseGoodRange(min, max)
  3569. real *min, *max;
  3570. #endif
  3571. /*Chooses a good range for data in min and max, returns in min and max*/
  3572. {
  3573.     /*If out of order, make in order*/
  3574.     if (*max <= *min)
  3575.     {
  3576.     *max = *min + 1.0;
  3577.     }
  3578.  
  3579.     if (*max > 0.0 && *min > 0.0)
  3580.     {
  3581.     /*Both positive*/
  3582.     real tryMin, tryMax;
  3583.     real expMin, expMax;
  3584.  
  3585.     expMin = rfloor(rlog10(*min));
  3586.     expMax = rceil(rlog10(*max));
  3587.  
  3588.     if (expMin < expMax - 1.0)
  3589.     {
  3590.         /*The min might as well be zero*/
  3591.         *min = 0.0;
  3592.     }
  3593.     else
  3594.     {
  3595.         *min = rpow(10.0, expMin);
  3596.     }
  3597.  
  3598.     tryMax = rpow(10.0, expMax);
  3599.  
  3600.     /*Try dividing by 5*/
  3601.     if (tryMax / 2.0 >= *max)
  3602.     {
  3603.         tryMax /= 2.0;
  3604.     }
  3605.     *max = tryMax;
  3606.     }
  3607.     else if (*max < 0.0 && *min < 0.0)
  3608.     {
  3609.     /*Both negative*/
  3610.     real tryMin, tryMax;
  3611.     real expMin, expMax;
  3612.  
  3613.     *min = -*min;
  3614.     *max = -*max;
  3615.  
  3616.     expMin = rfloor(rlog10(*min));
  3617.     expMax = rceil(rlog10(*max));
  3618.  
  3619.     if (expMin < expMax - 1.0)
  3620.     {
  3621.         /*The min might as well be zero*/
  3622.         *min = 0.0;
  3623.     }
  3624.     else
  3625.     {
  3626.         *min = rpow(10.0, expMin);
  3627.     }
  3628.  
  3629.     tryMax = rpow(10.0, expMax);
  3630.  
  3631.     /*Try dividing by 5*/
  3632.     if (tryMax / 2.0 >= *max)
  3633.     {
  3634.         tryMax /= 2.0;
  3635.     }
  3636.     *max = tryMax;
  3637.  
  3638.     *min = -*min;
  3639.     *max = -*max;
  3640.     }
  3641.     else
  3642.     {
  3643.     /*Span 0*/
  3644.     real tryMin, tryMax;
  3645.     real expMin, expMax;
  3646.  
  3647.     expMin = rfloor(rlog10(-*min));
  3648.     expMax = rceil(rlog10(*max));
  3649.  
  3650.     tryMax = rpow(10.0, expMax);
  3651.  
  3652.     /*Try dividing by 5*/
  3653.     if (tryMax / 2.0 >= *max)
  3654.     {
  3655.         tryMax /= 2.0;
  3656.     }
  3657.     *max = tryMax;
  3658.  
  3659.     tryMin = -rpow(10.0, expMin);
  3660.  
  3661.     /*Try dividing by 5*/
  3662.     if (tryMin / 2.0 <= *min)
  3663.     {
  3664.         tryMin /= 2.0;
  3665.     }
  3666.     *min = tryMin;
  3667.     }
  3668. }
  3669.  
  3670. static ObjPtr MakeCorralHelpString(object, class)
  3671. ObjPtr object, class;
  3672. /*Makes a corral help string for object in class*/
  3673. {
  3674.     if (GetPredicate(object, SINGLECORRAL))
  3675.     {
  3676.     SetVar(class, HELPSTRING, NewString("This corral can only hold a single icon.  You can select the icon by clicking it \
  3677. with the left mouse button \
  3678. or deselect it by clicking on the background.  If you drag another icon into this corral, \
  3679. it will replace any icon that is already there.  The icon can be deleted with the Delete \
  3680. item in the Object menu."));
  3681.     }
  3682.     else
  3683.     {
  3684.     SetVar(class, HELPSTRING, NewString("You can select a single icon within this corral by clicking it \
  3685. with the left mouse button.  \
  3686. You can select more than one icon by holding the Shift key down while you click on additional icons.  \
  3687. You can also click outside an icon and drag a rectangle around icons you would like to select.\n\
  3688. \n\
  3689. Items in the Object menu and some action buttons in the window \
  3690. will work on all selected objects."));
  3691.     }
  3692.     return ObjTrue;
  3693. }
  3694.  
  3695. #ifdef PROTO
  3696. Bool Select(ObjPtr obj, Bool flag)
  3697. #else
  3698. Bool Select(obj, flag)
  3699. ObjPtr obj;
  3700. Bool flag;
  3701. #endif
  3702. {
  3703.     ObjPtr repObj;
  3704.     FuncTyp selector;
  3705.     ObjPtr allSelected;
  3706.  
  3707.     if (runningScript && !scriptSelectP)
  3708.     {
  3709.     return true;
  3710.     }
  3711.  
  3712.     if (IsSelected(obj) == flag) return false;
  3713.  
  3714.     if (GetPredicate(obj, REPOBJONLY) && (repObj = GetVar(obj, REPOBJ)))
  3715.     {
  3716.     obj = repObj;
  3717.     }
  3718.  
  3719.     if (logging && scriptSelectP)
  3720.     {
  3721.     char logLine[256];
  3722.     MakeObjectName(tempStr, obj);
  3723.     if (tempStr[0])
  3724.     {
  3725.         sprintf(logLine, "%s %s\n", flag ? "select" : "deselect", tempStr);
  3726.         Log(logLine);
  3727.     }
  3728.     }
  3729.  
  3730.     selector = GetMethod(obj, SELECT);
  3731.     if (selector)
  3732.     {
  3733.     (* selector)(obj, flag);
  3734.     }
  3735.  
  3736.     /*Now do the selection*/
  3737.     allSelected = GetListVar("Select", objClass, ALLSELECTED);
  3738.     if (!allSelected) return;
  3739.  
  3740.     SetVar(obj, SELECTED, flag ? ObjTrue : ObjFalse);
  3741.     if (flag)
  3742.     {
  3743.     PrefixList(allSelected, obj);
  3744.     }
  3745.     else
  3746.     {
  3747.     DeleteFromList(allSelected, obj);
  3748.     }
  3749.     SetVar(objClass, ALLSELECTED, allSelected);
  3750.  
  3751.     /*Defer a task to update all the windows*/
  3752.     DoUniqueTask(AdjustObjButtons);
  3753.  
  3754.     return true;
  3755. }
  3756.  
  3757. void ForAllSelectedObjects(task)
  3758. FuncTyp task;
  3759. /*Does the specified task for all selected objects*/
  3760. {
  3761.     ThingListPtr runner, next;
  3762.     ObjPtr allSelected;
  3763.  
  3764.     allSelected = GetListVar("DeselectAll", objClass, ALLSELECTED);
  3765.     if (!allSelected) return;
  3766.  
  3767.     runner = LISTOF(allSelected);
  3768.     while (runner)
  3769.     {
  3770.     ObjPtr object;
  3771.     object = runner -> thing;
  3772.     runner = runner -> next;
  3773.     if (IsIcon(object))
  3774.     {
  3775.         object = GetVar(object, REPOBJ);
  3776.     }
  3777.     if (object)
  3778.     {
  3779.         ObjPtr truth;
  3780.         truth = (*task)(object);
  3781.     }
  3782.     }
  3783. }
  3784.  
  3785. #ifdef PROTO
  3786. Bool ParseInteger(int *value, char *s)
  3787. #else
  3788. Bool ParseInteger(value, s)
  3789. int *value;
  3790. char *s;
  3791. #endif
  3792. /*Parses an integer and puts it in value.  Returns true iff it was a good value.
  3793.   Prints out an error message and returns false if not*/
  3794. {
  3795.     char *t;
  3796.     double v;
  3797.     int intValue;
  3798.     int sign;
  3799.  
  3800.     /*First try to make a floating point value*/
  3801.     v = strtod(s, &t);
  3802.     if (s != t)
  3803.     {
  3804.     /*It made a number.  See if there's crap at the end*/
  3805.     while (*t)
  3806.     {
  3807.         if (!isspace(*t))
  3808.         {
  3809.         return false;
  3810.         }
  3811.         ++t;
  3812.     }
  3813.  
  3814.     intValue = v;
  3815.  
  3816.     if (intValue != v)
  3817.     {
  3818.         return false;
  3819.     }
  3820.     *value = intValue;
  3821.     return true;
  3822.     }
  3823.  
  3824.     return false;
  3825. }
  3826.  
  3827. #ifdef PROTO
  3828. Bool ParseReal(real *value, char *s)
  3829. #else
  3830. Bool ParseReal(value, s)
  3831. real *value;
  3832. char *s;
  3833. #endif
  3834. /*Parses a number in string s and puts it in value.  Returns true iff it
  3835.   was a good value.  Understands normal floating point plus INFINITY, -INFINITY,
  3836.   and MISSING.  Can be abbreviated to I and M, don't have to be upper case.*/
  3837. {
  3838.     char *t;
  3839.     double v;
  3840.     int sign;
  3841.  
  3842.     /*First try to make a floating point value*/
  3843.     v = strtod(s, &t);
  3844.     if (s != t)
  3845.     {
  3846.     /*It made a number.  See if there's crap at the end*/
  3847.     while (*t)
  3848.     {
  3849.         if (!isspace(*t))
  3850.         {
  3851.         return false;
  3852.         }
  3853.         ++t;
  3854.     }
  3855.     *value = v;
  3856.     return true;
  3857.     }
  3858.  
  3859.     sign = 1;
  3860.     /*OK, so search for infinity or missing*/
  3861.     t = s;
  3862.     SKIPBLANKS(t);
  3863.     if (*t == '+')
  3864.     {
  3865.     ++t;
  3866.     }
  3867.     else if (*t == '-')
  3868.     {
  3869.     sign = -1;
  3870.     ++t;
  3871.     }
  3872.     if (toupper(*t) == 'I')
  3873.     {
  3874.     /*Infinity*/
  3875.     *value = sign > 0 ? PLUSINF : MINUSINF;
  3876.     return true;
  3877.     }
  3878.     else if (toupper(*t) == 'M')
  3879.     {
  3880.     /*Missing data*/
  3881.     *value = missingData;
  3882.     return true;
  3883.     }
  3884.     else
  3885.     {
  3886.     return false;
  3887.     }
  3888. }
  3889.  
  3890. #ifdef PROTO
  3891. void PrintNumber(char *s, real value)
  3892. #else
  3893. void PrintNumber(s, value)
  3894. char *s;
  3895. real value;
  3896. #endif
  3897. /*Prints value into s*/
  3898. {
  3899.     if (value == missingData)
  3900.     {
  3901.     strcpy(s, "Missing");
  3902.     }
  3903.     else if (value >= PLUSINF)
  3904.     {
  3905.     strcpy(s, "Infinity");
  3906.     }
  3907.     else if (value <= MINUSINF)
  3908.     {
  3909.     strcpy(s, "-Infinity");
  3910.     }
  3911.     else
  3912.     {
  3913.     sprintf(s, "%g", (float) value);
  3914.     }
  3915. }
  3916.  
  3917. ObjPtr NewFlowLine(left, right, bottom, top, name)
  3918. int left, right, bottom, top;
  3919. char *name;
  3920. /*Creates a new flow line*/
  3921. {
  3922.     ObjPtr retVal;
  3923.  
  3924.     retVal = NewObject(flowLineClass, 0);
  3925.     Set2DIntBounds(retVal, left, right, bottom, top);
  3926.     SetVar(retVal, NAME, NewString(name));
  3927.     return retVal;
  3928. }
  3929.  
  3930. static ObjPtr DrawFlowLine(flowLine)
  3931. ObjPtr flowLine;
  3932. /*Draws a flow line*/
  3933. {
  3934.     int left, right, bottom, top, y;
  3935.  
  3936.     SetLineWidth(3);
  3937.  
  3938.     Get2DIntBounds(flowLine, &left, &right, &bottom, &top);
  3939.  
  3940.     y = (bottom + top) / 2;
  3941.  
  3942.     DrawUILine(left + ARROWLENGTH, y, right - ARROWLENGTH, y, UIBLACK);
  3943.  
  3944.     /*Draw half the arrow head*/
  3945.     FillUITri(right - ARROWLENGTH, y, right - ARROWLENGTH, y - ARROWHEIGHT, right, y, UIBLACK);
  3946.  
  3947.     /*Draw half the arrow head*/
  3948.     FillUITri(right - ARROWLENGTH, y, right - ARROWLENGTH, y + ARROWHEIGHT, right, y, UIBLACK);
  3949.  
  3950.     /*Draw half the arrow head*/
  3951.     FillUITri(left + ARROWLENGTH, y, left + ARROWLENGTH, y - ARROWHEIGHT, left, y, UIBLACK);
  3952.  
  3953.     /*Draw half the arrow head*/
  3954.     FillUITri(left + ARROWLENGTH, y, left + ARROWLENGTH, y + ARROWHEIGHT, left, y, UIBLACK);
  3955.  
  3956.     SetLineWidth(1);
  3957.     return ObjTrue;
  3958. }
  3959.  
  3960. #ifdef PROTO
  3961. void SetSelection(ObjPtr object, ObjPtr selection)
  3962. #else
  3963. void SetSelection(object, selection)
  3964. ObjPtr    object, selection;
  3965. #endif
  3966. /*Sets a selection within a control*/    
  3967. {
  3968.     FuncTyp setter;
  3969.     ObjPtr retVal;
  3970.  
  3971.     setter = GetMethod(object, SETSELECTION);
  3972.     if (setter)
  3973.     {
  3974.     (* setter) (object, selection);
  3975.     }
  3976. }
  3977.  
  3978. #ifdef PROTO
  3979. void ChangedSelection(ObjPtr object)
  3980. #else
  3981. void ChangedSelection(object)
  3982. ObjPtr object;
  3983. #endif
  3984. /*Does a CHANGEDSELECTION on a control*/
  3985. {
  3986.     FuncTyp changer;
  3987.  
  3988.     changer = GetMethod(object, CHANGEDSELECTION);
  3989.     if(changer)
  3990.     {
  3991.     InhibitLogging(true);
  3992.     (* changer)(object);
  3993.     InhibitLogging(false);
  3994.     }
  3995. }
  3996.  
  3997. static ObjPtr SelectScreenObj(object, selectp)
  3998. ObjPtr object;
  3999. Bool selectp;
  4000. /*Selects a screen object*/
  4001. {
  4002.     Bool alreadySelected;
  4003.  
  4004.     alreadySelected = IsSelected(object);
  4005.     if (selectp == alreadySelected)
  4006.     {
  4007.     return ObjTrue;
  4008.     }
  4009.  
  4010.     ImInvalid(object);
  4011.  
  4012.     return ObjTrue;
  4013. }
  4014.  
  4015. static ObjPtr ChangeDirectControlValue(control)
  4016. ObjPtr control;
  4017. /*Changes a Direct control's value*/
  4018. {
  4019.     ObjPtr repObj, var;
  4020.     NameTyp whichVar;
  4021.  
  4022.     repObj = GetVarSurely("ChangeDirectControlValue", control, REPOBJ);
  4023.     if (!repObj)
  4024.     {
  4025.     return ObjFalse;
  4026.     }
  4027.  
  4028.     var = GetSymbolVar("ChangeDirectControlValue", control, WHICHVAR);
  4029.     if (!var)
  4030.     {
  4031.     return ObjFalse;
  4032.     }
  4033.     whichVar = GetSymbolID(var);
  4034.  
  4035.     SetVar(repObj, whichVar, GetValue(control));
  4036.     ImInvalid(repObj);
  4037.     SetVar(control, APPEARANCE, ObjTrue);
  4038.  
  4039.     return ObjTrue;
  4040. }
  4041.  
  4042. static ObjPtr MakeDirectControlAppearance(control)
  4043. ObjPtr control;
  4044. /*Makes a Direct control's appearance based on the variable it controls*/
  4045. {
  4046.     ObjPtr repObj, var, value;
  4047.     NameTyp whichVar;
  4048.     FuncTyp method;
  4049.  
  4050.     repObj = GetVarSurely("MakeDirectControlAppearance", control, REPOBJ);
  4051.     if (!repObj)
  4052.     {
  4053.     return ObjFalse;
  4054.     }
  4055.  
  4056.     var = GetSymbolVar("MakeDirectControlAppearance", control, WHICHVAR);
  4057.     if (!var)
  4058.     {
  4059.     return ObjFalse;
  4060.     }
  4061.     whichVar = GetSymbolID(var);
  4062.  
  4063.     InhibitLogging(true);
  4064.     method = GetMethod(control, CHANGEDVALUE);
  4065.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  4066.     SetValue(control, GetVar(repObj, whichVar));
  4067.     SetMethod(control, CHANGEDVALUE, method);
  4068.     method = GetMethod(control, EXTRAAPPEARANCE);
  4069.     if (method)
  4070.     {
  4071.     (*method)(control);
  4072.     }
  4073.     ImInvalid(control);
  4074.     InhibitLogging(false);
  4075.     SetVar(control, APPEARANCE, ObjTrue);
  4076.  
  4077.     return ObjTrue;
  4078. }
  4079.  
  4080. #ifdef PROTO
  4081. void AssocDirectControlWithVar(ObjPtr control, ObjPtr object, NameTyp var)
  4082. #else
  4083. void AssocDirectControlWithVar(control, object, var)
  4084. ObjPtr control;
  4085. ObjPtr object;
  4086. NameTyp var;
  4087. #endif
  4088. /*Associates a control directly with a variable of an object.  The mapping
  4089.   from control to variable must be 1:1, and an ImInvalid must be an appropriate
  4090.   response to changing the variable
  4091. */
  4092. {
  4093.     SetVar(control, REPOBJ, object);
  4094.     SetVar(control, WHICHVAR, NewSymbol(var));
  4095.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  4096.     SetMethod(control, CHANGEDVALUE, ChangeDirectControlValue);
  4097.     SetMethod(control, APPEARANCE, MakeDirectControlAppearance);
  4098. }
  4099.  
  4100. static ObjPtr ChangeFlagControlValue(control)
  4101. ObjPtr control;
  4102. /*Changes a flag control's value*/
  4103. {
  4104.     ObjPtr repObj, var;
  4105.     NameTyp whichVar;
  4106.     int whichFlag, oldFlags;
  4107.     Bool flagOn;
  4108.  
  4109.     repObj = GetVarSurely("ChangeFlagControlValue", control, REPOBJ);
  4110.     if (!repObj)
  4111.     {
  4112.     return ObjFalse;
  4113.     }
  4114.  
  4115.     var = GetSymbolVar("ChangeFlagControlValue", control, WHICHVAR);
  4116.     if (!var)
  4117.     {
  4118.     return ObjFalse;
  4119.     }
  4120.     whichVar = GetSymbolID(var);
  4121.  
  4122.     var = GetIntVar("ChangeFlagControlValue", control, WHICHFLAG);
  4123.     if (!var)
  4124.     {
  4125.     return ObjFalse;
  4126.     }
  4127.     whichFlag = GetInt(var);
  4128.  
  4129.     var = GetVar(repObj, whichVar);
  4130.     if (var)
  4131.     {
  4132.     oldFlags = GetInt(var);
  4133.     }
  4134.     else
  4135.     {
  4136.     oldFlags = 0;
  4137.     }
  4138.  
  4139.     var = GetValue(control);
  4140.     if (!var)
  4141.     {
  4142.     return ObjFalse;
  4143.     }
  4144.     flagOn = IsTrue(var);
  4145.  
  4146.     if (flagOn)
  4147.     {
  4148.     oldFlags |= whichFlag;
  4149.     }
  4150.     else
  4151.     {
  4152.     oldFlags &= ~whichFlag;
  4153.     }
  4154.  
  4155.     SetVar(repObj, whichVar, NewInt(oldFlags));
  4156.     ImInvalid(repObj);
  4157.     SetVar(control, APPEARANCE, ObjTrue);
  4158.  
  4159.     return ObjTrue;
  4160. }
  4161.  
  4162. static ObjPtr MakeFlagControlAppearance(control)
  4163. ObjPtr control;
  4164. /*Makes a Flag control's appearance based on the variable it controls*/
  4165. {
  4166.     ObjPtr repObj, var, value;
  4167.     NameTyp whichVar;
  4168.     FuncTyp method;
  4169.     int whichFlag, oldFlags;
  4170.     ObjPtr newValue;
  4171.  
  4172.     repObj = GetVarSurely("MakeFlagControlAppearance", control, REPOBJ);
  4173.     if (!repObj)
  4174.     {
  4175.     return ObjFalse;
  4176.     }
  4177.  
  4178.     var = GetSymbolVar("MakeFlagControlAppearance", control, WHICHVAR);
  4179.     if (!var)
  4180.     {
  4181.     return ObjFalse;
  4182.     }
  4183.     whichVar = GetSymbolID(var);
  4184.  
  4185.     var = GetIntVar("MakeFlagControlAppearance", control, WHICHFLAG);
  4186.     if (!var)
  4187.     {
  4188.     return ObjFalse;
  4189.     }
  4190.     whichFlag = GetInt(var);
  4191.  
  4192.     var = GetVar(repObj, whichVar);
  4193.     if (var)
  4194.     {
  4195.     oldFlags = GetInt(var);
  4196.     }
  4197.     else
  4198.     {
  4199.     oldFlags = 0;
  4200.     }
  4201.  
  4202.     value = GetValue(control);
  4203.     newValue = oldFlags & whichFlag ? NewInt(1) : NewInt(0);
  4204.  
  4205.     if (!Equal(value, newValue))
  4206.     {
  4207.     InhibitLogging(true);
  4208.     method = GetMethod(control, CHANGEDVALUE);
  4209.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  4210.     SetValue(control, oldFlags & whichFlag ? NewInt(1) : NewInt(0));
  4211.     SetMethod(control, CHANGEDVALUE, method);
  4212.     method = GetMethod(control, EXTRAAPPEARANCE);
  4213.     if (method)
  4214.     {
  4215.     (*method)(control);
  4216.     }
  4217.     ImInvalid(control);
  4218.     InhibitLogging(false);
  4219.     SetVar(control, APPEARANCE, ObjTrue);
  4220.     }
  4221.  
  4222.     return ObjTrue;
  4223. }
  4224.  
  4225. #ifdef PROTO
  4226. void AssocFlagControlWithVar(ObjPtr control, ObjPtr object, NameTyp var, int whichFlag)
  4227. #else
  4228. void AssocFlagControlWithVar(control, object, var, whichFlag)
  4229. ObjPtr control;
  4230. ObjPtr object;
  4231. NameTyp var;
  4232. int whichFlag;
  4233. #endif
  4234. /*Associates a control directly with a flag of an object's variable.  The mapping
  4235.   from control to variable must be n:1, and an ImInvalid must be an appropriate
  4236.   response to changing the variable
  4237.   whichFlag is the flag, which should be a power of 2.  The control must have
  4238.   an integer value.
  4239. */
  4240. {
  4241.     SetVar(control, REPOBJ, object);
  4242.     SetVar(control, WHICHVAR, NewSymbol(var));
  4243.     SetVar(control, WHICHFLAG, NewInt(whichFlag));
  4244.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  4245.     SetMethod(control, CHANGEDVALUE, ChangeFlagControlValue);
  4246.     SetMethod(control, APPEARANCE, MakeFlagControlAppearance);
  4247. }
  4248.  
  4249. ObjPtr ShowTextRealMinMaxError(control)
  4250. ObjPtr control;
  4251. /*Shows a text real box's min max error*/
  4252. {
  4253.     WinInfoPtr errWindow;
  4254.     ObjPtr var;
  4255.     int controlFlags;
  4256.  
  4257.     var = GetVar(control, CONTROLFLAGS);
  4258.     if (var)
  4259.     {
  4260.     controlFlags = GetInt(var);
  4261.     }
  4262.     else
  4263.     {
  4264.     controlFlags = 0;
  4265.     }
  4266.  
  4267.     var = GetVar(control, MINMAX);
  4268.     if (var)
  4269.     {
  4270.     real *elements;
  4271.     char minString[40], maxString[40];
  4272.     elements = ELEMENTS(var);
  4273.     PrintNumber(minString, elements[0]);
  4274.     PrintNumber(maxString, elements[1]);
  4275.  
  4276.     sprintf(tempStr, "You have entered a number outside the allowed range of \
  4277. %c%s, %s%c.  Please try again.", (controlFlags & TR_NE_BOTTOM) ? '(' : '[',
  4278.         minString, maxString,
  4279.         (controlFlags & TR_NE_TOP) ? ')' : ']');
  4280.     }
  4281.     else
  4282.     {
  4283.     strcpy(tempStr, "You have entered a number outside the allowed range.  \
  4284. Please try again.");
  4285.     }
  4286.     if (runningScript)
  4287.     {
  4288.     fprintf(stderr, "The following error occured while reading the script\n(It is probably safe to ignore):\n");
  4289.     fprintf(stderr, "%s\n", tempStr);
  4290.     }
  4291.     else
  4292.     {
  4293.     errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, tempStr, 0, 0, "");
  4294.     SetVar((ObjPtr) errWindow, INHIBITLOGGING, ObjTrue);
  4295.     }
  4296.     return ObjTrue;
  4297. }
  4298.  
  4299. static ObjPtr ChangeTextRealControlValue(control)
  4300. ObjPtr control;
  4301. /*Changes a text real control's value*/
  4302. {
  4303.     ObjPtr repObj, var;
  4304.     NameTyp whichVar;
  4305.     int controlFlags;
  4306.     real minMax[2];
  4307.     real value;
  4308.     char *s;
  4309.  
  4310.     repObj = GetVarSurely("ChangeTextRealControlValue", control, REPOBJ);
  4311.     if (!repObj)
  4312.     {
  4313.     return ObjFalse;
  4314.     }
  4315.  
  4316.     var = GetSymbolVar("ChangeTextRealControlValue", control, WHICHVAR);
  4317.     if (!var)
  4318.     {
  4319.     return ObjFalse;
  4320.     }
  4321.     whichVar = GetSymbolID(var);
  4322.  
  4323.     var = GetVar(control, MINMAX);
  4324.     if (var)
  4325.     {
  4326.     Array2CArray(minMax, var);
  4327.     }
  4328.     else
  4329.     {
  4330.     minMax[0] = minusInf;
  4331.     minMax[1] = plusInf;
  4332.     }
  4333.  
  4334.     var = GetVar(control, CONTROLFLAGS);
  4335.     if (var)
  4336.     {
  4337.     controlFlags = GetInt(var);
  4338.     }
  4339.     else
  4340.     {
  4341.     controlFlags = 0;
  4342.     }
  4343.  
  4344.     var = GetValue(control);
  4345.     if ((!var) || (!IsString(var)))
  4346.     {
  4347.     return ObjFalse;
  4348.     }
  4349.  
  4350.     s = GetString(var);
  4351.  
  4352.     if (ParseReal(&value, s))
  4353.     {
  4354.     if (value == missingData)
  4355.     {
  4356.         if (0 == (controlFlags & TR_MISSING_OK))
  4357.         {
  4358.         WarnUser(CW_MISSINGERROR);
  4359.         return ObjFalse;
  4360.         }
  4361.     }
  4362.     else
  4363.     {
  4364.         if (controlFlags & TR_NE_BOTTOM)
  4365.         {
  4366.         if (value <= minMax[0])
  4367.         {
  4368.             DeferMessage(control, RANGEALERT);
  4369.             return ObjFalse;
  4370.         }
  4371.         }
  4372.         else
  4373.         {
  4374.         if (value < minMax[0])
  4375.         {
  4376.             DeferMessage(control, RANGEALERT);
  4377.             return ObjFalse;
  4378.         }
  4379.         }
  4380.  
  4381.         if (controlFlags & TR_NE_TOP)
  4382.         {
  4383.         if (value >= minMax[1])
  4384.         {
  4385.             DeferMessage(control, RANGEALERT);
  4386.             return ObjFalse;
  4387.         }
  4388.         }
  4389.         else
  4390.         {
  4391.         if (value > minMax[1])
  4392.         {
  4393.             DeferMessage(control, RANGEALERT);
  4394.             return ObjFalse;
  4395.         }
  4396.         }
  4397.         if (controlFlags & TR_INT_ONLY)
  4398.         {
  4399.         if (value != floor(value))
  4400.         {
  4401.             WarnUser(CW_NONINTERROR);
  4402.             return ObjFalse;
  4403.         }
  4404.         }
  4405.     }
  4406.  
  4407.     /*Dropped through, it must be OK*/
  4408.     SetVar(repObj, whichVar, NewReal(value));
  4409.     ImInvalid(repObj);
  4410.     }
  4411.     else
  4412.     {
  4413.     WarnUser(CW_NUMBERERROR);
  4414.     return ObjFalse;
  4415.     }
  4416.  
  4417.     SetVar(control, APPEARANCE, ObjTrue);
  4418.  
  4419.     return ObjTrue;
  4420. }
  4421.  
  4422. static ObjPtr MakeTextRealControlAppearance(control)
  4423. ObjPtr control;
  4424. /*Makes a text real control's appearance based on the variable it controls*/
  4425. {
  4426.     ObjPtr repObj, var, value;
  4427.     NameTyp whichVar;
  4428.     FuncTyp method;
  4429.  
  4430.     repObj = GetVarSurely("MakeTextRealControlAppearance", control, REPOBJ);
  4431.     if (!repObj)
  4432.     {
  4433.     return ObjFalse;
  4434.     }
  4435.  
  4436.     var = GetSymbolVar("MakeTextRealControlAppearance", control, WHICHVAR);
  4437.     if (!var)
  4438.     {
  4439.     return ObjFalse;
  4440.     }
  4441.     whichVar = GetSymbolID(var);
  4442.  
  4443.     var = GetRealVar("MakeTextRealControlAppearance", repObj, whichVar);
  4444.     if (var)
  4445.     {
  4446.     PrintNumber(tempStr, GetReal(var));
  4447.     }
  4448.     else
  4449.     {
  4450.     strcpy(tempStr, "");
  4451.     }
  4452.  
  4453.     InhibitLogging(true);
  4454.     method = GetMethod(control, CHANGEDVALUE);
  4455.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  4456.     SetValue(control, NewString(tempStr));
  4457.     SetMethod(control, CHANGEDVALUE, method);
  4458.     method = GetMethod(control, EXTRAAPPEARANCE);
  4459.     if (method)
  4460.     {
  4461.     (*method)(control);
  4462.     }
  4463.     ImInvalid(control);
  4464.     InhibitLogging(false);
  4465.     SetVar(control, APPEARANCE, ObjTrue);
  4466.  
  4467.     return ObjTrue;
  4468. }
  4469.  
  4470. #ifdef PROTO
  4471. void AssocTextRealControlWithVar(ObjPtr control, ObjPtr object, NameTyp var, real min, real max, int flags)
  4472. #else
  4473. void AssocTextRealControlWithVar(control, object, var, min, max, flags)
  4474. ObjPtr control;
  4475. ObjPtr object;
  4476. real min, max;
  4477. NameTyp var;
  4478. int flags;
  4479. #endif
  4480. /*Associates a control with a text real value with a variable of an object.
  4481.   An ImInvalid must be an appropriate response to changing the variable
  4482. */
  4483. {
  4484.     ObjPtr minMax;
  4485.     real *elements;
  4486.  
  4487.     SetVar(control, REPOBJ, object);
  4488.     SetVar(control, WHICHVAR, NewSymbol(var));
  4489.     minMax = NewRealArray(1, 2L);
  4490.     elements = ELEMENTS(minMax);
  4491.     elements[0] = min;
  4492.     elements[1] = max;
  4493.     SetVar(control, MINMAX, minMax);
  4494.     SetVar(control, CONTROLFLAGS, NewInt(flags));
  4495.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  4496.     SetMethod(control, RANGEALERT, ShowTextRealMinMaxError);
  4497.     SetMethod(control, CHANGEDVALUE, ChangeTextRealControlValue);
  4498.     SetMethod(control, APPEARANCE, MakeTextRealControlAppearance);
  4499. }
  4500.  
  4501. static ObjPtr ChangeTextIntControlValue(control)
  4502. ObjPtr control;
  4503. /*Changes a text int control's value*/
  4504. {
  4505.     ObjPtr repObj, var;
  4506.     NameTyp whichVar;
  4507.     int controlFlags;
  4508.     real minMax[2];
  4509.     int value;
  4510.     char *s;
  4511.  
  4512.     repObj = GetVarSurely("ChangeTextIntControlValue", control, REPOBJ);
  4513.     if (!repObj)
  4514.     {
  4515.     return ObjFalse;
  4516.     }
  4517.  
  4518.     var = GetSymbolVar("ChangeTextIntControlValue", control, WHICHVAR);
  4519.     if (!var)
  4520.     {
  4521.     return ObjFalse;
  4522.     }
  4523.     whichVar = GetSymbolID(var);
  4524.  
  4525.     var = GetVar(control, MINMAX);
  4526.     if (var)
  4527.     {
  4528.     Array2CArray(minMax, var);
  4529.     }
  4530.     else
  4531.     {
  4532.     minMax[0] = minusInf;
  4533.     minMax[1] = plusInf;
  4534.     }
  4535.  
  4536.     var = GetVar(control, CONTROLFLAGS);
  4537.     if (var)
  4538.     {
  4539.     controlFlags = GetInt(var);
  4540.     }
  4541.     else
  4542.     {
  4543.     controlFlags = 0;
  4544.     }
  4545.  
  4546.     var = GetValue(control);
  4547.     if ((!var) || (!IsString(var)))
  4548.     {
  4549.     return ObjFalse;
  4550.     }
  4551.  
  4552.     s = GetString(var);
  4553.  
  4554.     if (ParseInteger(&value, s))
  4555.     {
  4556.     if (value < minMax[0])
  4557.     {
  4558.         DeferMessage(control, RANGEALERT);
  4559.         return ObjFalse;
  4560.     }
  4561.     if (value > minMax[1])
  4562.     {
  4563.         DeferMessage(control, RANGEALERT);
  4564.         return ObjFalse;
  4565.     }
  4566.  
  4567.     /*Dropped through, it must be OK*/
  4568.     SetVar(repObj, whichVar, NewInt(value));
  4569.     ImInvalid(repObj);
  4570.     }
  4571.     else
  4572.     {
  4573.     WarnUser(CW_NUMBERERROR);
  4574.     return ObjFalse;
  4575.     }
  4576.  
  4577.     SetVar(control, APPEARANCE, ObjTrue);
  4578.  
  4579.     return ObjTrue;
  4580. }
  4581.  
  4582. static ObjPtr MakeTextIntControlAppearance(control)
  4583. ObjPtr control;
  4584. /*Makes a text int control's appearance based on the variable it controls*/
  4585. {
  4586.     ObjPtr repObj, var, value;
  4587.     NameTyp whichVar;
  4588.     FuncTyp method;
  4589.  
  4590.     repObj = GetVarSurely("MakeTextIntControlAppearance", control, REPOBJ);
  4591.     if (!repObj)
  4592.     {
  4593.     return ObjFalse;
  4594.     }
  4595.  
  4596.     var = GetSymbolVar("MakeTextIntControlAppearance", control, WHICHVAR);
  4597.     if (!var)
  4598.     {
  4599.     return ObjFalse;
  4600.     }
  4601.     whichVar = GetSymbolID(var);
  4602.  
  4603.     var = GetIntVar("MakeTextIntControlAppearance", repObj, whichVar);
  4604.     if (var)
  4605.     {
  4606.     PrintNumber(tempStr, GetReal(var));
  4607.     }
  4608.     else
  4609.     {
  4610.     strcpy(tempStr, "");
  4611.     }
  4612.  
  4613.     InhibitLogging(true);
  4614.     method = GetMethod(control, CHANGEDVALUE);
  4615.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  4616.     SetValue(control, NewString(tempStr));
  4617.     SetMethod(control, CHANGEDVALUE, method);
  4618.     method = GetMethod(control, EXTRAAPPEARANCE);
  4619.     if (method)
  4620.     {
  4621.     (*method)(control);
  4622.     }
  4623.     ImInvalid(control);
  4624.     InhibitLogging(false);
  4625.     SetVar(control, APPEARANCE, ObjTrue);
  4626.  
  4627.     return ObjTrue;
  4628. }
  4629.  
  4630. #ifdef PROTO
  4631. void AssocTextIntControlWithVar(ObjPtr control, ObjPtr object, NameTyp var, real min, real max, int flags)
  4632. #else
  4633. void AssocTextIntControlWithVar(control, object, var, min, max, flags)
  4634. ObjPtr control;
  4635. ObjPtr object;
  4636. real min, max;
  4637. NameTyp var;
  4638. int flags;
  4639. #endif
  4640. /*Associates a control with a text int value with a variable of an object.
  4641.   An ImInvalid must be an appropriate response to changing the variable
  4642. */
  4643. {
  4644.     ObjPtr minMax;
  4645.     real *elements;
  4646.  
  4647.     SetVar(control, REPOBJ, object);
  4648.     SetVar(control, WHICHVAR, NewSymbol(var));
  4649.     minMax = NewRealArray(1, 2L);
  4650.     elements = ELEMENTS(minMax);
  4651.     elements[0] = min;
  4652.     elements[1] = max;
  4653.     SetVar(control, MINMAX, minMax);
  4654.     SetVar(control, CONTROLFLAGS, NewInt(flags));
  4655.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  4656.     SetMethod(control, RANGEALERT, ShowTextRealMinMaxError);
  4657.     SetMethod(control, CHANGEDVALUE, ChangeTextIntControlValue);
  4658.     SetMethod(control, APPEARANCE, MakeTextIntControlAppearance);
  4659. }
  4660.  
  4661. static ObjPtr ChangeIndexedTextRealControlValue(control)
  4662. ObjPtr control;
  4663. /*Changes an indexed text real control's value*/
  4664. {
  4665.     ObjPtr repObj, var;
  4666.     NameTyp whichVar;
  4667.     long whichIndex;
  4668.     long nIndices;
  4669.     long k;
  4670.     real *el1, *el2;
  4671.     int controlFlags;
  4672.     real minMax[2];
  4673.     real value;
  4674.     char *s;
  4675.  
  4676.     repObj = GetVarSurely("ChangeIndexedTextRealControlValue", control, REPOBJ);
  4677.     if (!repObj)
  4678.     {
  4679.     return ObjFalse;
  4680.     }
  4681.  
  4682.     var = GetSymbolVar("ChangeIndexedTextRealControlValue", control, WHICHVAR);
  4683.     if (!var)
  4684.     {
  4685.     return ObjFalse;
  4686.     }
  4687.     whichVar = GetSymbolID(var);
  4688.  
  4689.     var = GetIntVar("ChangeIndexedTextRealControlValue", control, WHICHINDEX);
  4690.     if (!var)
  4691.     {
  4692.     return ObjFalse;
  4693.     }
  4694.     whichIndex = GetInt(var);
  4695.  
  4696.     var = GetVar(control, MINMAX);
  4697.     if (var)
  4698.     {
  4699.     Array2CArray(minMax, var);
  4700.     }
  4701.     else
  4702.     {
  4703.     minMax[0] = minusInf;
  4704.     minMax[1] = plusInf;
  4705.     }
  4706.  
  4707.     var = GetVar(control, CONTROLFLAGS);
  4708.     if (var)
  4709.     {
  4710.     controlFlags = GetInt(var);
  4711.     }
  4712.     else
  4713.     {
  4714.     controlFlags = 0;
  4715.     }
  4716.  
  4717.     var = GetValue(control);
  4718.     if ((!var) || (!IsString(var)))
  4719.     {
  4720.     return ObjFalse;
  4721.     }
  4722.  
  4723.     s = GetString(var);
  4724.  
  4725.     if (ParseReal(&value, s))
  4726.     {
  4727.     if (value == missingData)
  4728.     {
  4729.         if (0 == (controlFlags & TR_MISSING_OK))
  4730.         {
  4731.         WarnUser(CW_MISSINGERROR);
  4732.         return ObjFalse;
  4733.         }
  4734.     }
  4735.     else
  4736.     {
  4737.         if (controlFlags & TR_NE_BOTTOM)
  4738.         {
  4739.         if (value <= minMax[0])
  4740.         {
  4741.             DeferMessage(control, RANGEALERT);
  4742.             return ObjFalse;
  4743.         }
  4744.         }
  4745.         else
  4746.         {
  4747.         if (value < minMax[0])
  4748.         {
  4749.             DeferMessage(control, RANGEALERT);
  4750.             return ObjFalse;
  4751.         }
  4752.         }
  4753.  
  4754.         if (controlFlags & TR_NE_TOP)
  4755.         {
  4756.         if (value >= minMax[1])
  4757.         {
  4758.             DeferMessage(control, RANGEALERT);
  4759.             return ObjFalse;
  4760.         }
  4761.         }
  4762.         else
  4763.         {
  4764.         if (value > minMax[1])
  4765.         {
  4766.             DeferMessage(control, RANGEALERT);
  4767.             return ObjFalse;
  4768.         }
  4769.         }
  4770.  
  4771.     }
  4772.  
  4773.     /*Dropped through, it must be OK*/
  4774.     var = GetArrayVar("ChangeIndexedTextRealControlValue", repObj, whichVar);
  4775.     if (!var)
  4776.     {
  4777.         return ObjFalse;
  4778.     }
  4779.     el1 = ELEMENTS(var);
  4780.     nIndices = DIMS(var)[0];
  4781.     var = NewRealArray(1, nIndices);
  4782.     el2 = ELEMENTS(var);
  4783.     for (k = 0; k < nIndices; ++k)
  4784.     {
  4785.         el2[k] = el1[k];
  4786.     }
  4787.     el2[whichIndex] = value;
  4788.     SetVar(repObj, whichVar, var);
  4789.  
  4790.     ImInvalid(repObj);
  4791.     }
  4792.     else
  4793.     {
  4794.     WarnUser(CW_NUMBERERROR);
  4795.     return ObjFalse;
  4796.     }
  4797.  
  4798.     SetVar(control, APPEARANCE, ObjTrue);
  4799.  
  4800.     return ObjTrue;
  4801. }
  4802.  
  4803. static ObjPtr MakeIndexedTextRealControlAppearance(control)
  4804. ObjPtr control;
  4805. /*Makes a text real control's appearance based on the variable it controls*/
  4806. {
  4807.     ObjPtr repObj, var, value;
  4808.     NameTyp whichVar;
  4809.     long whichIndex;
  4810.     FuncTyp method;
  4811.  
  4812.     repObj = GetVarSurely("MakeIndexedTextRealControlAppearance", control, REPOBJ);
  4813.     if (!repObj)
  4814.     {
  4815.     return ObjFalse;
  4816.     }
  4817.  
  4818.     var = GetSymbolVar("MakeIndexedTextRealControlAppearance", control, WHICHVAR);
  4819.     if (!var)
  4820.     {
  4821.     return ObjFalse;
  4822.     }
  4823.     whichVar = GetSymbolID(var);
  4824.  
  4825.     var = GetIntVar("MakeIndexedTextRealControlAppearance", control, WHICHINDEX);
  4826.     if (!var)
  4827.     {
  4828.     return ObjFalse;
  4829.     }
  4830.     whichIndex = GetInt(var);
  4831.  
  4832.     var = GetArrayVar("MakeIndexedTextRealControlAppearance", repObj, whichVar);
  4833.     if (var)
  4834.     {
  4835.     real *elements;
  4836.     elements = ELEMENTS(var);
  4837.  
  4838.     PrintNumber(tempStr, elements[whichIndex]);
  4839.     }
  4840.     else
  4841.     {
  4842.     strcpy(tempStr, "");
  4843.     }
  4844.  
  4845.     InhibitLogging(true);
  4846.     method = GetMethod(control, CHANGEDVALUE);
  4847.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  4848.     SetValue(control, NewString(tempStr));
  4849.     SetMethod(control, CHANGEDVALUE, method);
  4850.     method = GetMethod(control, EXTRAAPPEARANCE);
  4851.     if (method)
  4852.     {
  4853.     (*method)(control);
  4854.     }
  4855.     ImInvalid(control);
  4856.     InhibitLogging(false);
  4857.     SetVar(control, APPEARANCE, ObjTrue);
  4858.  
  4859.     return ObjTrue;
  4860. }
  4861.  
  4862. #ifdef PROTO
  4863. void AssocIndexedTextRealControlWithVar(ObjPtr control, ObjPtr object, NameTyp var, long whichIndex, real min, real max, int flags)
  4864. #else
  4865. void AssocIndexedTextRealControlWithVar(control, object, var, whichIndex, min, max, flags)
  4866. ObjPtr control;
  4867. ObjPtr object;
  4868. NameTyp var;
  4869. long whichIndex;
  4870. real min, max;
  4871. int flags;
  4872. #endif
  4873. /*Associates a control with a text real value with an indexed variable of an object.
  4874.   An ImInvalid must be an appropriate response to changing the variable
  4875. */
  4876. {
  4877.     ObjPtr minMax;
  4878.     real *elements;
  4879.  
  4880.     SetVar(control, REPOBJ, object);
  4881.     SetVar(control, WHICHVAR, NewSymbol(var));
  4882.     minMax = NewRealArray(1, 2L);
  4883.     elements = ELEMENTS(minMax);
  4884.     elements[0] = min;
  4885.     elements[1] = max;
  4886.     SetVar(control, MINMAX, minMax);
  4887.     SetVar(control, CONTROLFLAGS, NewInt(flags));
  4888.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  4889.     SetVar(control, WHICHINDEX, NewInt(whichIndex));
  4890.     SetMethod(control, RANGEALERT, ShowTextRealMinMaxError);
  4891.     SetMethod(control, CHANGEDVALUE, ChangeIndexedTextRealControlValue);
  4892.     SetMethod(control, APPEARANCE, MakeIndexedTextRealControlAppearance);
  4893. }
  4894.  
  4895. static ObjPtr ChangeColorControlValue(control)
  4896. ObjPtr control;
  4897. /*Changes a color control's value*/
  4898. {
  4899.     ObjPtr repObj, var;
  4900.     NameTyp whichVar;
  4901.     real hsv[3], rgb[3];
  4902.     real hs[2];
  4903.  
  4904.     repObj = GetVarSurely("ChangeColorControlValue", control, REPOBJ);
  4905.     if (!repObj)
  4906.     {
  4907.     return ObjFalse;
  4908.     }
  4909.  
  4910.     var = GetSymbolVar("ChangeColorControlValue", control, WHICHVAR);
  4911.     if (!var)
  4912.     {
  4913.     return ObjFalse;
  4914.     }
  4915.     whichVar = GetSymbolID(var);
  4916.  
  4917.     var = GetVar(repObj, whichVar);
  4918.     if (!var)
  4919.     {
  4920.     var = GetVar(control, OLDVAR);
  4921.     }
  4922.     if (!var)
  4923.     {
  4924.     rgb[0] = rgb[1] = rgb[2] = 0.0;
  4925.     }
  4926.     else if (IsRealArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3)
  4927.     {
  4928.     Array2CArray(rgb, var);
  4929.     }
  4930.     else if (IsInt(var))
  4931.     {
  4932.     rgb[0] = uiColors[GetInt(var)][0] / 255.0;
  4933.     rgb[1] = uiColors[GetInt(var)][1] / 255.0;
  4934.     rgb[2] = uiColors[GetInt(var)][2] / 255.0;
  4935.     }
  4936.     else
  4937.     {
  4938.     ReportError("ChangeColorControlValue", "Bad color value");
  4939.     }
  4940.     RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), rgb[0], rgb[1], rgb[2]);
  4941.  
  4942.     var = GetValue(control);
  4943.     if (!var)
  4944.     {
  4945.     return ObjFalse;
  4946.     }
  4947.     Array2CArray(hs, var);
  4948.     hsv[0] = hs[0];
  4949.     hsv[1] = hs[1];
  4950.  
  4951.     HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]);
  4952.  
  4953.     var = NewRealArray(1, 3L);
  4954.     CArray2Array(var, rgb);
  4955.  
  4956.     SetVar(repObj, whichVar, var);
  4957.     ImInvalid(repObj);
  4958.     SetVar(control, APPEARANCE, ObjTrue);
  4959.  
  4960.     return ObjTrue;
  4961. }
  4962.  
  4963. static ObjPtr PasteColorControl(control)
  4964. ObjPtr control;
  4965. /*Pastes color into a color control*/
  4966. {
  4967.     ObjPtr repObj, var;
  4968.     NameTyp whichVar;
  4969.     ObjPtr color;
  4970.  
  4971.     color = FromClipboard();
  4972.  
  4973.     repObj = GetVarSurely("PasteColorControl", control, REPOBJ);
  4974.     if (!repObj)
  4975.     {
  4976.     return ObjFalse;
  4977.     }
  4978.  
  4979.     var = GetSymbolVar("PasteColorControl", control, WHICHVAR);
  4980.     if (!var)
  4981.     {
  4982.     return ObjFalse;
  4983.     }
  4984.     whichVar = GetSymbolID(var);
  4985.  
  4986.     if (IsRealArray(color) && RANK(color) == 1 && DIMS(color)[0] == 3)
  4987.     {
  4988.     /*Set the object's var to this*/
  4989.     SetVar(repObj, whichVar, color);
  4990.     MakeObjectName(tempStr, repObj);
  4991.  
  4992.     Log("begin snapshot ");
  4993.     Log(tempStr);
  4994.     Log("\n");
  4995.     LogVariable(repObj, whichVar);
  4996.     Log("end snapshot\n");
  4997.  
  4998.     ImInvalid(repObj);
  4999.     }
  5000.     else if (IsRealArray(color) && RANK(color) == 1 && DIMS(color)[0] == 2)
  5001.     {
  5002.     real hsv[3], rgb[3];
  5003.     real hs[2];
  5004.  
  5005.     var = GetVar(repObj, whichVar);
  5006.     if (!var)
  5007.     {
  5008.     var = GetVar(control, OLDVAR);
  5009.     }
  5010.     if (!var)
  5011.     {
  5012.     rgb[0] = rgb[1] = rgb[2] = 0.0;
  5013.     }
  5014.     else if (IsRealArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3)
  5015.     {
  5016.     Array2CArray(rgb, var);
  5017.     }
  5018.     else if (IsInt(var))
  5019.     {
  5020.     rgb[0] = uiColors[GetInt(var)][0] / 255.0;
  5021.     rgb[1] = uiColors[GetInt(var)][1] / 255.0;
  5022.     rgb[2] = uiColors[GetInt(var)][2] / 255.0;
  5023.     }
  5024.     else
  5025.     {
  5026.     PasteError(control, color);
  5027.     }
  5028.     RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), rgb[0], rgb[1], rgb[2]);
  5029.  
  5030.     Array2CArray(hs, color);
  5031.     hsv[0] = hs[0];
  5032.     hsv[1] = hs[1];
  5033.  
  5034.     HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]);
  5035.  
  5036.     var = NewRealArray(1, 3L);
  5037.     CArray2Array(var, rgb);
  5038.  
  5039.     SetVar(repObj, whichVar, var);
  5040.     ImInvalid(repObj);
  5041.     SetVar(control, APPEARANCE, ObjTrue);
  5042.     }
  5043.     return ObjTrue;
  5044. }
  5045.  
  5046. static ObjPtr MakeColorControlAppearance(control)
  5047. ObjPtr control;
  5048. /*Makes a color control's appearance based on the variable it controls*/
  5049. {
  5050.     ObjPtr repObj, var, value;
  5051.     NameTyp whichVar;
  5052.     FuncTyp method;
  5053.     real hsv[3], rgb[3];
  5054.  
  5055.     repObj = GetVarSurely("MakeColorControlAppearance", control, REPOBJ);
  5056.     if (!repObj)
  5057.     {
  5058.     return ObjFalse;
  5059.     }
  5060.  
  5061.     var = GetSymbolVar("MakeColorControlAppearance", control, WHICHVAR);
  5062.     if (!var)
  5063.     {
  5064.     return ObjFalse;
  5065.     }
  5066.     whichVar = GetSymbolID(var);
  5067.  
  5068.     var = GetVar(repObj, whichVar);
  5069.     if (!var)
  5070.     {
  5071.     return ObjFalse;
  5072.     }
  5073.     if (IsRealArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3)
  5074.     {
  5075.     Array2CArray(rgb, var);
  5076.     }
  5077.     else if (IsInt(var))
  5078.     {
  5079.     rgb[0] = uiColors[GetInt(var)][0] / 255.0;
  5080.     rgb[1] = uiColors[GetInt(var)][1] / 255.0;
  5081.     rgb[2] = uiColors[GetInt(var)][2] / 255.0;
  5082.     }
  5083.     else
  5084.     {
  5085.     ReportError("MakeColorControlAppearance", "Bad color value");
  5086.     }
  5087.     SetVar(control, OLDVAR, var);
  5088.     RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), rgb[0], rgb[1], rgb[2]);
  5089.  
  5090.     InhibitLogging(true);
  5091.     method = GetMethod(control, CHANGEDVALUE);
  5092.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  5093.     var = NewRealArray(1, 2L);
  5094.     CArray2Array(var, hsv);
  5095.     SetValue(control, var);
  5096.     SetMethod(control, CHANGEDVALUE, method);
  5097.     method = GetMethod(control, EXTRAAPPEARANCE);
  5098.     if (method)
  5099.     {
  5100.     (*method)(control);
  5101.     }
  5102.     ImInvalid(control);
  5103.     InhibitLogging(false);
  5104.     SetVar(control, APPEARANCE, ObjTrue);
  5105.  
  5106.     return ObjTrue;
  5107. }
  5108.  
  5109. #ifdef PROTO
  5110. void AssocColorControlWithVar(ObjPtr control, ObjPtr object, NameTyp var)
  5111. #else
  5112. void AssocColorControlWithVar(control, object, var)
  5113. ObjPtr control;
  5114. ObjPtr object;
  5115. NameTyp var;
  5116. #endif
  5117. /*Associates a color directly with a variable of an object.  The mapping
  5118.   from control to variable must be 1:1, and an ImInvalid must be an appropriate
  5119.   response to changing the variable
  5120. */
  5121. {
  5122.     SetVar(control, REPOBJ, object);
  5123.     SetVar(control, WHICHVAR, NewSymbol(var));
  5124.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  5125.     SetMethod(control, CHANGEDVALUE, ChangeColorControlValue);
  5126.     SetMethod(control, APPEARANCE, MakeColorControlAppearance);
  5127.     SetMethod(control, PASTE, PasteColorControl);
  5128. }
  5129.  
  5130. static ObjPtr ChangeBrightnessControlValue(control)
  5131. ObjPtr control;
  5132. /*Changes a brightness control's value*/
  5133. {
  5134.     ObjPtr repObj, var;
  5135.     NameTyp whichVar;
  5136.     real hsv[3], rgb[3];
  5137.  
  5138.     repObj = GetVarSurely("ChangeBrightnessControlValue", control, REPOBJ);
  5139.     if (!repObj)
  5140.     {
  5141.     return ObjFalse;
  5142.     }
  5143.  
  5144.     var = GetSymbolVar("ChangeBrightnessControlValue", control, WHICHVAR);
  5145.     if (!var)
  5146.     {
  5147.     return ObjFalse;
  5148.     }
  5149.     whichVar = GetSymbolID(var);
  5150.  
  5151.     var = GetVar(repObj, whichVar);
  5152.     if (!var)
  5153.     {
  5154.     var = GetVar(control, OLDVAR);
  5155.     }
  5156.     if (!var)
  5157.     {
  5158.     rgb[0] = rgb[1] = rgb[2] = 0.0;
  5159.     }
  5160.     else if (IsRealArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3)
  5161.     {
  5162.     Array2CArray(rgb, var);
  5163.     }
  5164.     else if (IsInt(var))
  5165.     {
  5166.     rgb[0] = uiColors[GetInt(var)][0] / 255.0;
  5167.     rgb[1] = uiColors[GetInt(var)][1] / 255.0;
  5168.     rgb[2] = uiColors[GetInt(var)][2] / 255.0;
  5169.     }
  5170.     else
  5171.     {
  5172.     ReportError("ChangeBrightnessControlValue", "Bad color value");
  5173.     }
  5174.     RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), rgb[0], rgb[1], rgb[2]);
  5175.  
  5176.     var = GetValue(control);
  5177.     if (!var)
  5178.     {
  5179.     return ObjFalse;
  5180.     }
  5181.     hsv[2] = GetReal(var);
  5182.  
  5183.     HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]);
  5184.  
  5185.     var = NewRealArray(1, 3L);
  5186.     CArray2Array(var, rgb);
  5187.  
  5188.     SetVar(repObj, whichVar, var);
  5189.     ImInvalid(repObj);
  5190.     SetVar(control, APPEARANCE, ObjTrue);
  5191.  
  5192.     return ObjTrue;
  5193. }
  5194.  
  5195. static ObjPtr MakeBrightnessControlAppearance(control)
  5196. ObjPtr control;
  5197. /*Makes a color control's appearance based on the variable it controls*/
  5198. {
  5199.     ObjPtr repObj, var, value;
  5200.     NameTyp whichVar;
  5201.     FuncTyp method;
  5202.     real hsv[3], rgb[3];
  5203.  
  5204.     repObj = GetVarSurely("MakeBrightnessControlAppearance", control, REPOBJ);
  5205.     if (!repObj)
  5206.     {
  5207.     return ObjFalse;
  5208.     }
  5209.  
  5210.     var = GetSymbolVar("MakeBrightnessControlAppearance", control, WHICHVAR);
  5211.     if (!var)
  5212.     {
  5213.     return ObjFalse;
  5214.     }
  5215.     whichVar = GetSymbolID(var);
  5216.  
  5217.     var = GetVar(repObj, whichVar);
  5218.     if (!var)
  5219.     {
  5220.     return ObjFalse;
  5221.     }
  5222.     if (IsRealArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3)
  5223.     {
  5224.     Array2CArray(rgb, var);
  5225.     }
  5226.     else if (IsInt(var))
  5227.     {
  5228.     rgb[0] = uiColors[GetInt(var)][0] / 255.0;
  5229.     rgb[1] = uiColors[GetInt(var)][1] / 255.0;
  5230.     rgb[2] = uiColors[GetInt(var)][2] / 255.0;
  5231.     }
  5232.     else
  5233.     {
  5234.     ReportError("MakeBrightnessControlAppearance", "Bad color value");
  5235.     }
  5236.     SetVar(control, OLDVAR, var);
  5237.     RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), rgb[0], rgb[1], rgb[2]);
  5238.  
  5239.     InhibitLogging(true);
  5240.     method = GetMethod(control, CHANGEDVALUE);
  5241.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  5242.     SetValue(control, NewReal(hsv[2]));
  5243.     SetMethod(control, CHANGEDVALUE, method);
  5244.     method = GetMethod(control, EXTRAAPPEARANCE);
  5245.     if (method)
  5246.     {
  5247.     (*method)(control);
  5248.     }
  5249.     ImInvalid(control);
  5250.     InhibitLogging(false);
  5251.     SetVar(control, APPEARANCE, ObjTrue);
  5252.  
  5253.     return ObjTrue;
  5254. }
  5255.  
  5256. #ifdef PROTO
  5257. void AssocBrightnessControlWithVar(ObjPtr control, ObjPtr object, NameTyp var)
  5258. #else
  5259. void AssocBrightnessControlWithVar(control, object, var)
  5260. ObjPtr control;
  5261. ObjPtr object;
  5262. NameTyp var;
  5263. #endif
  5264. /*Associates a brightness control with a variable of an object.  The mapping
  5265.   from control to variable must be 1:1, and an ImInvalid must be an appropriate
  5266.   response to changing the variable
  5267. */
  5268. {
  5269.     SetVar(control, REPOBJ, object);
  5270.     SetVar(control, WHICHVAR, NewSymbol(var));
  5271.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  5272.     SetMethod(control, CHANGEDVALUE, ChangeBrightnessControlValue);
  5273.     SetMethod(control, APPEARANCE, MakeBrightnessControlAppearance);
  5274. }
  5275.  
  5276. static ObjPtr ChangeInhibitControlValue(control)
  5277. ObjPtr control;
  5278. /*Changes an inhibit control's value*/
  5279. {
  5280.     ObjPtr repObj, var;
  5281.     NameTyp whichVar;
  5282.  
  5283.     repObj = GetVarSurely("ChangeInhibitControlValue", control, REPOBJ);
  5284.     if (!repObj)
  5285.     {
  5286.     return ObjFalse;
  5287.     }
  5288.  
  5289.     var = GetSymbolVar("ChangeDirectControlValue", control, WHICHVAR);
  5290.     if (!var)
  5291.     {
  5292.     return ObjFalse;
  5293.     }
  5294.     whichVar = GetSymbolID(var);
  5295.  
  5296.     var = GetValue(control);
  5297.     if (IsTrue(var))
  5298.     {
  5299.     SetVar(repObj, whichVar, NULLOBJ);
  5300.     }
  5301.     else
  5302.     {
  5303.     SetVar(repObj, whichVar, GetVar(control, OLDVAR));
  5304.     }
  5305.     ImInvalid(repObj);
  5306.     SetVar(control, APPEARANCE, ObjTrue);
  5307.  
  5308.     return ObjTrue;
  5309. }
  5310.  
  5311. static ObjPtr MakeInhibitControlAppearance(control)
  5312. ObjPtr control;
  5313. /*Makes an inhibit control's appearance based on the variable it controls*/
  5314. {
  5315.     ObjPtr repObj, var, value;
  5316.     NameTyp whichVar;
  5317.     FuncTyp method;
  5318.  
  5319.     repObj = GetVarSurely("MakeInhibitControlAppearance", control, REPOBJ);
  5320.     if (!repObj)
  5321.     {
  5322.     return ObjFalse;
  5323.     }
  5324.  
  5325.     var = GetSymbolVar("MakeInhibitControlAppearance", control, WHICHVAR);
  5326.     if (!var)
  5327.     {
  5328.     return ObjFalse;
  5329.     }
  5330.     whichVar = GetSymbolID(var);
  5331.  
  5332.     InhibitLogging(true);
  5333.     method = GetMethod(control, CHANGEDVALUE);
  5334.     SetMethod(control, CHANGEDVALUE, (FuncTyp) 0);
  5335.     var = GetVar(repObj, whichVar);
  5336.     if (var)
  5337.     {
  5338.     SetVar(control, OLDVAR, var);
  5339.     SetValue(control, NewInt(0));
  5340.     }
  5341.     else
  5342.     {
  5343.     SetValue(control, NewInt(1));
  5344.     }
  5345.  
  5346.     SetMethod(control, CHANGEDVALUE, method);
  5347.     InhibitLogging(false);
  5348.     ImInvalid(repObj);
  5349.     SetVar(control, APPEARANCE, ObjTrue);
  5350.  
  5351.     return ObjTrue;
  5352. }
  5353.  
  5354. #ifdef PROTO
  5355. void AssocInhibitControlWithVar(ObjPtr control, ObjPtr object, NameTyp var, ObjPtr oldVal)
  5356. #else
  5357. void AssocInhibitControlWithVar(control, object, var, oldVal)
  5358. ObjPtr control;
  5359. ObjPtr object;
  5360. NameTyp var;
  5361. ObjPtr oldVal;
  5362. #endif
  5363. /*Associates an inhibit with a variable of an object.  The mapping
  5364.   from control to variable must be 1:1, and an ImInvalid must be an appropriate
  5365.   response to changing the variable
  5366.  
  5367.   An inhibit control sets the variable it controls to NULLOBJ when it is on
  5368.   and puts it back the way it was when turned off.  Other controls which control
  5369.   the same thing must use a similar method.  Right now, this is intended to
  5370.   work with brightness and color controls.  oldVal is an initial old value
  5371. */
  5372. {
  5373.     SetVar(control, REPOBJ, object);
  5374.     SetVar(control, WHICHVAR, NewSymbol(var));
  5375.     DeclareIndirectDependency(control, APPEARANCE, REPOBJ, var);
  5376.     SetVar(control, OLDVAR, oldVal);
  5377.     SetMethod(control, CHANGEDVALUE, ChangeInhibitControlValue);
  5378.     SetMethod(control, APPEARANCE, MakeInhibitControlAppearance);
  5379. }
  5380.  
  5381. ObjPtr MakeSaveButtonAppearance(object)
  5382. ObjPtr object;
  5383. /*Makes a save button's APPEARANCE*/
  5384. {
  5385.     ActivateButton(object, true);
  5386.     SetVar(object, APPEARANCE, ObjTrue);
  5387.     return ObjTrue;
  5388. }
  5389.  
  5390. ObjPtr SaveButtonChanged(object)
  5391. ObjPtr object;
  5392. /*Changes a save button*/
  5393. {
  5394.     ObjPtr repObj;
  5395.  
  5396.     ActivateButton(object, false);
  5397.     SetVar(object, APPEARANCE, ObjTrue);
  5398.     repObj = GetVar((ObjPtr) object, REPOBJ);
  5399.     if (repObj)
  5400.     {
  5401.     Log("save controls");
  5402.     DeferMessage(repObj, SAVECPANEL);
  5403.     }
  5404.     return ObjTrue;
  5405. }
  5406.  
  5407. ObjPtr ChangeControlPanelButton(object)
  5408. ObjPtr object;
  5409. /*Changedvalue for a control button*/
  5410. {
  5411.     ObjPtr panel, panelContents, value, curButton, parent;
  5412.  
  5413.     value = GetValue(object);
  5414.  
  5415.     parent = GetVar(object, PARENT);
  5416.     curButton = GetVar(parent, BUTTON);
  5417.  
  5418.     if (value && IsInt(value) && 0 == GetInt(value) && curButton != object)
  5419.     {
  5420.     panel = GetObjectVar("ChangeControlPanelButton", object, PANEL);
  5421.     panelContents = GetListVar("ChangeControlPanelButton", object, PANELCONTENTS);
  5422.     if (panel && panelContents)
  5423.     {
  5424.         ThingListPtr runner;
  5425.  
  5426.         if (!GetPredicate(object, CONTROLSADDED))
  5427.         {
  5428.         /*Have to add controls*/
  5429.         FuncTyp method;
  5430.         ObjPtr repObj;
  5431.  
  5432.         SetVar(object, CONTROLSADDED, ObjTrue);
  5433.         repObj = GetObjectVar("ChangeControlPanelButton", object, REPOBJ);
  5434.         if (repObj)
  5435.         {
  5436.             method = GetMethod(object, ADDCONTROLS);
  5437.             if (method)
  5438.             {
  5439.             (*method)(repObj, panelContents);
  5440.             }
  5441.  
  5442.             /*Make a save settings button*/
  5443.             if (GetPredicate(object, CANSAVESETTINGS))
  5444.             {
  5445.             ObjPtr button, list;
  5446.  
  5447.             button = TemplateButton(SettingsTemplate, "Save All Settings");
  5448.             PrefixList(panelContents, button);
  5449.             SetVar(button, PARENT, panel);
  5450.             SetVar(button, REPOBJ, repObj);
  5451.             SetVar(button, HELPSTRING, NewString("Press this button to save all \
  5452. the settings for this object to a disk file.  Every setting for this object, \
  5453. including settings set through other control panels, will be saved.\n\n\
  5454. Settings are saved in a subdirectory named .scianSettings in your home directory.  \
  5455. If that directory does not exist, it will automatically be created.  Settings are \
  5456. saved in a file with a name of the form <name>.<type> where <name> is the name of \
  5457. the object (with spaces converted to underscores) and <type> is a string indicating the type \
  5458. of the object.\n\n\
  5459. For example, the controls for the LVR-5000 recorder driver will be stored in a \
  5460. file named LVR-5000.recdvr in the directory ~/.scianSettings.  The files are actually \
  5461. fragments of scripts.  Do not edit them unless you are really adventurous."));
  5462.             ActivateButton(button, false);
  5463.             list = AssembleSnapVars(repObj);
  5464.             if (list)
  5465.             {
  5466.                 ThingListPtr runner;
  5467.  
  5468.                 runner = LISTOF(list);
  5469.                 while (runner)
  5470.                 {
  5471.                 NameTyp symbolID;
  5472.  
  5473.                 symbolID = GetSymbolID(runner -> thing);
  5474.                 DeclareIndirectDependency(button, APPEARANCE, REPOBJ, symbolID);
  5475.             
  5476.                 runner = runner -> next;
  5477.                 }
  5478.             }
  5479.             SetVar(button, APPEARANCE, ObjTrue);
  5480.             SetMethod(button, APPEARANCE, MakeSaveButtonAppearance);
  5481.             SetMethod(button, CHANGEDVALUE, SaveButtonChanged);
  5482.             }
  5483.         }
  5484.         }
  5485.  
  5486.         runner = LISTOF(panelContents);
  5487.         while (runner)
  5488.         {
  5489.         SetVar(runner -> thing, PARENT, panel);
  5490.         runner = runner -> next;
  5491.         }
  5492.         SetVar(panel, CONTENTS, panelContents);
  5493.         if (curButton)
  5494.         {
  5495.         SetVar(curButton, VALUE, NewInt(0));
  5496.         }
  5497.         SetVar(object, VALUE, NewInt(1));
  5498.         SetVar(parent, BUTTON, object);
  5499.         ImInvalid(panel);
  5500.         return ObjTrue;
  5501.     }
  5502.     else
  5503.     {
  5504.         return ObjFalse;
  5505.     }
  5506.     }
  5507.     else
  5508.     {
  5509.     return ObjTrue;
  5510.     }
  5511. }
  5512.  
  5513. void InitControls()
  5514. /*Initializes controls*/
  5515. {
  5516.     ObjPtr list;
  5517.     ObjPtr allSelected;
  5518.  
  5519.     allSelected = NewList();
  5520.     SetVar(objClass, ALLSELECTED, allSelected);
  5521.  
  5522.     screenClass = NewObject(NULLOBJ, 0);
  5523.     AddToReferenceList(screenClass);
  5524.     SetMethod(screenClass, DELETE, DeleteObject);
  5525.     DeclareDependency(screenClass, APPEARANCE, SELECTED);
  5526.     SetMethod(screenClass, SELECT, SelectScreenObj);
  5527.  
  5528.     controlClass = NewObject(screenClass, 0);
  5529.     AddToReferenceList(controlClass);
  5530.     list = NewList();
  5531.     PrefixList(list, NewSymbol(VALUE));
  5532.     SetVar(controlClass, SNAPVARS, list);
  5533.     SetVar(controlClass, TYPESTRING, NewString("control"));
  5534.     SetVar(controlClass, ACTIVATED, ObjTrue);
  5535.     SetMethod(controlClass, SHOWCONTROLS, NewControlWindow);
  5536.     SetVar(controlClass, STICKINESS, NewInt(STICKYTOP + STICKYLEFT));
  5537.  
  5538.     panelClass = NewObject(controlClass, 0);
  5539.     AddToReferenceList(panelClass);
  5540.     SetVar(panelClass, CLASSID, NewInt(CLASS_PANEL));
  5541.     SetVar(panelClass, NAME, NewString("Panel"));
  5542. #ifdef GRAPHICS
  5543.     SetMethod(panelClass, DRAW, DrawPanel);
  5544. #endif
  5545.     SetMethod(panelClass, BOUNDSINVALID, PanelBoundsInvalid);
  5546. #ifdef INTERACTIVE
  5547.     SetMethod(panelClass, PRESS, PressPanel);
  5548.     SetMethod(panelClass, DROPOBJECTS, DropInPanel);
  5549.     SetMethod(panelClass, KEYDOWN, KeyDownContents);
  5550. #endif
  5551.     greyPanelClass = NewObject(panelClass, 0);
  5552.     AddToReferenceList(greyPanelClass);
  5553.     SetVar(greyPanelClass, STICKINESS, NewInt(STICKYTOP + STICKYRIGHT + STICKYBOTTOM + STICKYLEFT));
  5554.     SetVar(greyPanelClass, BACKGROUND, NewInt(UIBACKGROUND));
  5555.  
  5556.     fieldClass = NewObject(controlClass, 0);
  5557.     AddToReferenceList(fieldClass);
  5558. #ifdef GRAPHICS
  5559.     SetMethod(fieldClass, DRAW, DrawField);
  5560. #endif
  5561. #ifdef INTERACTIVE
  5562.     SetMethod(fieldClass, PRESS, PressField);
  5563. #endif
  5564.     SetVar(fieldClass, NAME, NewString("Field"));
  5565.     SetMethod(fieldClass, FINDOBJECT, FindObjectField);
  5566.     SetMethod(fieldClass, FORALLOBJECTS, ForAllFieldObjects);
  5567.     SetVar(fieldClass, TYPESTRING, NewString("field"));
  5568.     SetMethod(fieldClass, BOUNDSINVALID, FieldBoundsInvalid);
  5569. #ifdef INTERACTIVE
  5570.     SetMethod(fieldClass, PRESSCONTENTS, PressFieldContents);
  5571.     SetMethod(fieldClass, KEYDOWN, KeyDownContents);
  5572. #endif
  5573. #ifndef DONTCLIP
  5574.     SetVar(fieldClass, OPAQUE, ObjTrue);
  5575. #endif
  5576.  
  5577.     corralClass = NewObject(fieldClass, 0);
  5578.     AddToReferenceList(corralClass);
  5579.     SetVar(corralClass, CLASSID, NewInt(CLASS_CORRAL));
  5580.     SetVar(corralClass, NAME, NewString("Corral"));
  5581.     SetVar(corralClass, VIEWBYWHAT, NewInt(VB_ICON));
  5582. #ifdef GRAPHICS
  5583.     SetMethod(corralClass, DRAWCONTENTS, DrawCorralContents);
  5584. #endif
  5585. #ifdef INTERACTIVE 
  5586.     SetMethod(corralClass, PRESSCONTENTS, PressCorralContents);
  5587.     SetMethod(corralClass, DROPOBJECTS, DropInCorral);
  5588. #endif
  5589.     SetMethod(corralClass, RECALCSCROLL, RecalcCorralScroll);
  5590.     SetMethod(corralClass, RESHAPE, ReshapeCorral);
  5591.     SetVar(corralClass, TYPESTRING, NewString("icon corral"));
  5592.     SetMethod(corralClass, MAKE1HELPSTRING, MakeCorralHelpString);
  5593.  
  5594.     switchClass = NewObject(controlClass, 0);
  5595.     AddToReferenceList(switchClass);
  5596.     SetVar(switchClass, NAME, NewString("Switch"));
  5597. #ifdef GRAPHICS
  5598.     SetMethod(switchClass, DRAW, DrawSwitch);
  5599. #endif
  5600. #ifdef INTERACTIVE
  5601.     SetMethod(switchClass, PRESS, PressSwitch);
  5602. #endif
  5603.     SetMethod(switchClass, SETVAL, SetSwitchVal);
  5604.     SetVar(switchClass, TYPESTRING, NewString("data switch"));
  5605.     SetVar(switchClass, HELPSTRING, NewString("To change the data path within a switch, click on the data path you desire."));
  5606.  
  5607.     controlFieldClass = NewObject(fieldClass, 0);
  5608.     AddToReferenceList(controlFieldClass);
  5609. #ifdef GRAPHICS
  5610.     SetMethod(controlFieldClass, DRAW, DrawControlField);
  5611.     SetMethod(controlFieldClass, DRAWCONTENTS, DrawControlFieldContents);
  5612. #endif
  5613.     SetMethod(controlFieldClass, RECALCSCROLL, RecalcControlFieldScroll);
  5614.     SetMethod(controlFieldClass, RESHAPE, ReshapeCorral);
  5615.     SetVar(controlFieldClass, TYPESTRING, NewString("field"));
  5616.  
  5617.     flowLineClass = NewObject(controlClass, 0);
  5618.     SetMethod(flowLineClass, DRAW, DrawFlowLine);
  5619.     AddToReferenceList(flowLineClass);
  5620.  
  5621.     InitButtons();
  5622.     InitSliders();
  5623.     InitTextBoxes();
  5624.     InitScales();
  5625.     InitPerspecControls();
  5626.     InitTitleBoxes();
  5627.     InitTrackControls();
  5628.     InitColorControls();
  5629. }
  5630.  
  5631. void KillControls()
  5632. /*Kills the controls*/
  5633. {
  5634.     KillColorControls();
  5635.     KillTrackControls();
  5636.     KillTitleBoxes();
  5637.     KillPerspecControls();
  5638.     KillScales();
  5639.     KillTextBoxes();
  5640.     KillSliders();
  5641.     KillButtons();
  5642.     RemoveFromReferenceList(flowLineClass);
  5643.     RemoveFromReferenceList(controlFieldClass);
  5644.     RemoveFromReferenceList(switchClass);
  5645.     RemoveFromReferenceList(corralClass);
  5646.     RemoveFromReferenceList(fieldClass);
  5647.     RemoveFromReferenceList(greyPanelClass);
  5648.     RemoveFromReferenceList(panelClass);
  5649.     RemoveFromReferenceList(controlClass);
  5650.     RemoveFromReferenceList(screenClass);
  5651. }
  5652.  
  5653.